jcommsc's People
Forkers
cckmitjcommsc's Issues
Tomcat
Tomcat
- Bootstrap 是Tomcat 默认的引导启动了, 我们平时 执行 ${catalina.base}/bin/startup.sh 就是 将 Bootstrap 当做 main 类 进行启动(PS: Bootstrap 有个非常重要的功能, 就是定义整个程序的 classLoader 层级, 这个在 Classloader 中会详细叙述)
- Catalina 在 Tomcat 中, Catalina其实就是代表了整个 服务控制中心, 其控制着整个 Tomcat 的 start, stop, await, 配置文件测试, 将配置文件 server.xml 解析成对应的 StandardServer, 触发 StandardServer 及其子组件的 init, start, stop, destory 等操作
- Server 一个Tomcat程序, 一个 Server, 上面 Catalina 的 start, stop, await 其实都是代理 Server 操作的, 而Catalina 又比 Server 多了 解析配置文件 server.xml
- Service 在代码层面看到, 理论上一个 Server可以包含多个 Service, 而Service 对应多个 请求连接处理器 connector 与一个子容器 Container, 另一个非常重要的属性就是 Mapper (路由模块)
- Mapper 请求路由模块, 这个模块里面的数据就是整个容器的各个层级的容器的信息, 每次容器中有组件变化, 就会触发 MapperListener, 而MapperListener 又会触发Mapper 里面数据的变化(PS:Tomcat支持动态增加容器, 而当容器变化时, 对应的路由信息也要进行相应的变化, 这个工作就交由 MapperListener来完成)
在进行路由请求时, 请求连接器 connector 将通过 Service 获取对应 路由模块Mapper 进行路由操作 - Engine 连接器connector 接到请求, 通过路由模块就能找到对应的 Engine, 并且整个消息经过容器的第一层就是 Engine, 那Engine 是什么作用呢? 路由到请求的 host, 在整个 Tomcat 中可能有好几个 Host
(一个host其实就是代表一个域名, 而大家也知道, 现在的一塔物理机可以同时又好几个域名指向它), 所以需要 Engine 进行路由 (PS: 在产线上一般都是一台物理机器 一个Tomcat, 而 Engine 默认路由的也是其 defaultHost)
见 ${catalina.base}/conf/server.xml 中的 "" 现在是不是有点感觉了 - Host 一个host其实就是代表一个域名, 这里的Host 主要完成 Context的部署(deployOnStartup, 默认目录 ${catalina.base}/webapps/)/自动部署(autoDeploy), host 层面的配置文件的解析, 在部署环节需要 HostConfig 进行相应操作 (HostConfig非常重要)
- Context 代表Tomcat容器里面的一个项目, 也就是我们平时在 ${catalina.base}/webapps/ 下面放的一个 war 包 (其中包括 WEB-INF/lib, WEB-INF/classes, web.xml 等)
- Wrapper 一个Servlet 就代表一个 Wrapper(单例模式), 所有的请求都会被servlet来处理(JSP 由JSPServlet来处理, 静态文件由WebdavServlet来处理), 现在一般项目都由 Spring 的 Dispatcherservlet 来统一处理, 而Dispatcherservlet 又非常大
当然 Tomcat 也支持 一个线程一个 Servlet这种线程安全的 Servlet 模式, 每个Servlet 最多对应 20个实例, 若出现第21个请求来(针对同一个 Servlet), 请求就会被阻塞掉 (啃爹哇, 若使用这种模式 + Spring的DispatchServlet 则Tomcat的并发请求就被限制在20了...) - ApplicationFilterChain 这是一条 Filter 的处理链, 程序会根据URI匹配对应的 Filter, 最后设置 Servlet, 程序会依次执行 ApplicationFilterChain里面的Filter(通过递归), 最后执行对应的 Servlet (到这里只是处理了 Servlet 里面的业务逻辑), 而正真的写数据是在 CoyoteAdapter 中的 response.finishResponse()
对了还有一个 PipeLine(管道) + Valve(阀门)
11. PipeLine 每个容器都有其对应的 PipeLine, PipeLine 里面装载着 Valve(以链表的形式), 此时是不是想到了 netty 里面的 ChannelPipeline, 只是 netty 里面叫做 valve 叫做了 ChannelHandler, 并且由其 ChannelHandlerContext 控制了链表的结构
到这里, 大家可能会困惑, 干嘛定义这么多对象, 直接定义一个 请求连接处理模块 + 一个 封装Servlet的模块 不久行了
额 没事 我们来看一下这个
Example: 我自己的服务器, 假设 IP: 23.89.15.9, 在这个服务器上有两个域名指向它, 一个是 www.tuomatuo.com, 一个是 localhost
场景一: 请求 URL = http:www.tuomatuo.com:8080/manager/login.do
(1). www.tuomatuo.com 就代表组件中的 Host
(2). manager 代表我们在 ${catalina.base}/webapps/ 下面部署的运用, 也就是 Host 的子容器 Context
(3). login.do 就是 Servlet匹配的URI了, 你可以假想成代表 Wrapper
场景二: 请求 URL = http:localhost:8080/taobao/index.do
(1). localhost 就代表组件中的 Host
(2). taobao 代表我们在 ${catalina.base}/webapps/ 下面部署的运用, 也就是 Host 的子容器 Context
(3). index.do 就是 Servlet匹配的URI了, 你可以假想成代表 Wrapper
从上面的两个场景中, 我们得知 Tomcat 支持多 Host, 并且每个 Host 下面可以部署多个 Context, 每个Context 下面也可以有多个 Servlet
Tomcat 线程模型
这张图勾画出了NioEndpoint的大致执行流程图,worker线程并没有体现出来,它是作为一个线程池不断的执行IO读写事件即SocketProcessor(一个Runnable),即这里的Poller仅仅监听Socket的IO事件,然后封装成一个个的SocketProcessor交给worker线程池来处理。下面我们来详细的介绍下NioEndpoint中的Acceptor、Poller、SocketProcessor。
它们处理客户端连接的主要流程如图所示:
常见问题
tomcat 为什么会被进程杀掉
可能是linux的内存保护机制,在进程发生OOM的时候,杀掉进程。如果不希望,可以通过配置更改。
tomcat 异步请求原理
网络安全
网络安全
HttpOnly Secure
基于安全的考虑,需要给cookie加上Secure和HttpOnly属性,HttpOnly比较好理解,设置HttpOnly=true的cookie不能被js获取到,无法用document.cookie打出cookie的内容。
Secure属性是说如果一个cookie被设置了Secure=true,那么这个cookie只能用https协议发送给服务器,用http协议是不发送的。换句话说,cookie是在https的情况下创建的,而且他的Secure=true,那么之后你一直用https访问其他的页面(比如登录之后点击其他子页面),cookie会被发送到服务器,你无需重新登录就可以跳转到其他页面。但是如果这是你把url改成http协议访问其他页面,你就需要重新登录了,因为这个cookie不能在http协议中发送。
Java linux 问题排查常用命令
系统级别
内存以及CPU
free
free -m
free: free命令显示系统的所有内存的使用情况,包括空闲内存、被使用的内存和交换内存空间。Free命令显示也包括一些内核使用的缓存和缓冲区的信息。
-m 以M形式展示数据
top
任务管理器
find
根据名称查找/目录下的filename.txt文件
###网络
netstat
netstat -anp|grep 8080
根据端口查看运行的进程:
netstat -anp|grep 端口号 或 lsof -i:端口号
find / -name filename.txt
tcpdump
tcpdump host 172.16.29.40 and port 4600 -X -s 500
tcp 抓包命令
抓取本机进程发往指定端口的请求:tcpdump -A dst port 8080
##进程级别
查找进程
ps -ef |grep java
执行命令$ps -ef|grep tomcat 你就能找出tomcat占据的进程号,当然这要求tomcat启动了。
jps-v
JVM
JVM配置
-XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:./gclogs
jstack命令的语法格式: jstack 。可以用jps查看java进程id。
jstat
jstack 1234
主要是对java应用程序的资源和性能进行实时的命令行监控,包括了对heap size和垃圾回收状况的监控。
jstat -gc 28933 2000 2 显示gc 的使用情况
jstat -gcutil 28933 2000 2 显示gc 比例
jmap
查看进程号为1234的Java程序的整个jvm内存状态
jmap -heap 1234
查找进程号为1234的java程序的jvm堆中对象详细占用情况
jmap -histo 1234
导出堆文件
jmap -dump:format=b,file=heap3.bin 24327
jstatk
查看线程快照
jstack pid
设计模式
设计模式
代理模式
public interface IMath {
double add(double x, double y);
}
public class Math implements IMath {
public double add(double x, double y) {
return 0;
}
}
public class MathProxy implements IMath {
private Math math;
public MathProxy() throws Exception {
math = (Math) Class.forName("_design_mode._proxy_mode.Math").newInstance();
}
public double add(double x, double y) {
return 0;
}
}
public class MyProgram {
public static void main(String[] args) throws Exception {
MathProxy p=new MathProxy();
System.out.println(p.add(1, 1));
}
}
Spring AOP
工厂模式
Spring工厂模式 BeanFactory
单例模式
public class Singleton {
private Singleton(){
}
private static class SingletonHolder{
private final static Singleton instance=new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
策略模式
public class Client {
public static void main(String[] args) {
//选择并创建需要使用的策略对象
MemberStrategy strategy = new IntermediateMemberStrategy();
//创建环境
Price price = new Price(strategy);
//计算价格
double quote = price.quote(300);
System.out.println("图书的最终价格为:" + quote);
}
static class IntermediateMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于中级会员的折扣为10%");
return booksPrice * 0.9;
}
}
static class Price {
//持有一个具体的策略对象
private MemberStrategy strategy;
/**
* 构造函数,传入一个具体的策略对象
* @param strategy 具体的策略对象
*/
public Price(MemberStrategy strategy){
this.strategy = strategy;
}
/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double quote(double booksPrice){
return this.strategy.calcPrice(booksPrice);
}
}
static class PrimaryMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于初级会员的没有折扣");
return booksPrice;
}
}
interface MemberStrategy {
/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double calcPrice(double booksPrice);
}
}
原型模式
class Resume implements Serializable,Cloneable {
/**
*
*/
private static final long serialVersionUID = 8614140644886700330L;
private String name;
private String sex;
private Integer age;
private WorkExperience work;
public Resume(String name){
this.name = name;
work = new WorkExperience();
}
//设置个人信息
public void setPersonalInfo(String sex, Integer age){
this.sex = sex;
this.age = age;
}
//设置工作经历
public void setWorkExperience(String workDate,String company){
work.setWorkDate(workDate);
work.setCompany(company);
}
//显示
public void display(){
System.out.println(String.format("%s %s %s", name,sex,age));
System.out.println(String.format("工作经历:%s %s", work.getWorkDate(), work.getCompany()));
}
//浅复制
public Object clone(){
Object obj = null;
try {
obj = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return obj;
}
//深复制
public Object deepClone() throws IOException, ClassNotFoundException{
//将对象写到流里
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(this);
//从流里读出来
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
return (oi.readObject());
}
}
// --------------------------------------------------------------------------------
/**
* 工作经历类
*
*/
class WorkExperience implements Serializable {
private static final long serialVersionUID = -5461562344310808271L;
private String workDate;
public String getWorkDate() {
return workDate;
}
public void setWorkDate(String workDate) {
this.workDate = workDate;
}
private String company;
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
}
// --------------------------------------------------------------------------------
/**
* 客户端调用
*
*/
public class Prototype {
public static void main(String[] args) throws ClassNotFoundException, IOException {
Resume a = new Resume("大鸟");
a.setPersonalInfo("男", 29);
a.setWorkExperience("1998-2000", "xx公司");
//浅复制
Resume b = (Resume)a.clone();
b.setPersonalInfo("男", 25);
b.setWorkExperience("1998-2006", "yy公司");
a.display();
b.display();
// 运行结果:a和b的WorkExperience的引用值是一样的,改变b的WorkExperience值,a也会变化
// 大鸟 男 29
// 工作经历:1998-2006 yy公司
// 大鸟 男 25
// 工作经历:1998-2006 yy公司
// demo2
Resume c = new Resume("大鸟");
c.setPersonalInfo("男", 29);
c.setWorkExperience("1998-2000", "xx公司");
//深复制
Resume d = (Resume)c.deepClone();
d.setPersonalInfo("男", 25);
d.setWorkExperience("1998-2006", "yy公司");
c.display();
d.display();
// 运行结果:a和b的WorkExperience的引用值是不同的
// 大鸟 男 29
// 工作经历:1998-2000 xx公司
// 大鸟 男 25
// 工作经历:1998-2006 yy公司
}
模版模式
public class TemplateMethod {
public static void main(String[] args) {
Account account = new MoneyMarketAccount();
System.out.println("货币市场账号的利息数额为:" + account.calculateInterest());
account = new CDAccount();
System.out.println("定期账号的利息数额为:" + account.calculateInterest());
}
}
abstract class Account {
/**
* 模板方法,计算利息数额
* @return 返回利息数额
*/
public final double calculateInterest(){
double interestRate = doCalculateInterestRate();
String accountType = doCalculateAccountType();
double amount = calculateAmount(accountType);
return amount * interestRate;
}
/**
* 基本方法留给子类实现
*/
protected abstract String doCalculateAccountType();
/**
* 基本方法留给子类实现
*/
protected abstract double doCalculateInterestRate();
/**
* 基本方法,已经实现
*/
private double calculateAmount(String accountType){
/**
* 省略相关的业务逻辑
*/
return 7243.00;
}
}
class MoneyMarketAccount extends Account {
@Override
protected String doCalculateAccountType() {
return "Money Market";
}
@Override
protected double doCalculateInterestRate() {
return 0.045;
}
}
class CDAccount extends Account {
@Override
protected String doCalculateAccountType() {
return "Certificate of Deposite";
}
@Override
protected double doCalculateInterestRate() {
return 0.06;
}
}
Spring Bean 生命周期
实例化Bean对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。而createBean最终调用 doCreateBean(beanName, mbdToUse, args)完成类的Bean的创建。
doCreateBean做了3件事
/**
* Actually create the specified bean. Pre-creation processing has already happened
* at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
* <p>Differentiates between default bean instantiation, use of a
* factory method, and autowiring a constructor.
* @param beanName the name of the bean
* @param mbd the merged bean definition for the bean
* @param args explicit arguments to use for constructor or factory method invocation
* @return a new instance of the bean
* @throws BeanCreationException if the bean could not be created
* @see #instantiateBean
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
*/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException {
// Instantiate the bean.1.包装对象
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// Initialize the bean instance. 2.初始化bean
Object exposedObject = bean;
try {
//2.1填充属性
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
//2.2初始化Bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.3 注册DisposableBeand的方法
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
-
对于ApplicationContext容器,当容器启动结束后,便实例化所有的bean。 容器通过获取BeanDefinition对象中的信息进行实例化。并且这一步仅仅是简单的实例化,并未进行依赖注入。 实例化对象被包装在BeanWrapper对象中,BeanWrapper提供了设置对象属性的接口,从而避免了使用反射机制设置属性。
/**
- Initialize the given BeanWrapper with the custom editors registered
- with this factory. To be called for BeanWrappers that will create
- and populate bean instances.
-
The default implementation delegates to {@link #registerCustomEditors}.
- Can be overridden in subclasses.
- @param bw the BeanWrapper to initialize
*/
protected void initBeanWrapper(BeanWrapper bw) {
bw.setConversionService(getConversionService());
registerCustomEditors(bw);
}
-
设置对象属性(依赖注入)实例化后的对象被封装在BeanWrapper对象中,并且此时对象仍然是一个原生的状态,并没有进行依赖注入。 紧接着,Spring根据BeanDefinition中的信息进行依赖注入。 并且通过BeanWrapper提供的设置属性的接口完成依赖注入。
/**
填充对象属性-
Populate the bean instance in the given BeanWrapper with the property values
-
from the bean definition.
-
@param beanName the name of the bean
-
@param mbd the bean definition for the bean
-
@param bw BeanWrapper with bean instance
*/
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}if (!continueWithPropertyPopulation) {
return;
}if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);// Add property values based on autowire by name if applicable. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}applyPropertyValues(beanName, mbd, bw, pvs);
}
-
/**
* Initialize the given bean instance, applying factory callbacks
* as well as init methods and bean post processors.
* <p>Called from {@link #createBean} for traditionally defined beans,
* and from {@link #initializeBean} for existing bean instances.
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the bean definition that the bean was created with
* (can also be {@code null}, if given an existing bean instance)
* @return the initialized bean instance (potentially wrapped)
* @see BeanNameAware
* @see BeanClassLoaderAware
* @see BeanFactoryAware
* @see #applyBeanPostProcessorsBeforeInitialization
* @see #invokeInitMethods
* @see #applyBeanPostProcessorsAfterInitialization
*/
//3-6的步骤在这个方法里完成
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
//注入aware属性
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
//调用BeanPostProcessor.Before方法
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
//调用InitializingBean.afterPropertiesSet 然后反射调用init-method
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
//调用BeanPostProcessor.After方法
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
-
注入Aware接口紧接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给bean。
-
BeanPostProcessor当经过上述几个步骤后,bean对象已经被正确构造,但如果你想要对象被使用前再进行一些自定义的处理,就可以通过BeanPostProcessor接口实现。 该接口提供了两个函数:postProcessBeforeInitialzation( Object bean, String beanName ) 当前正在初始化的bean对象会被传递进来,我们就可以对这个bean作任何处理。 这个函数会先于InitialzationBean执行,因此称为前置处理。 所有Aware接口的注入就是在这一步完成的。
-
InitializingBean与init-method当BeanPostProcessor的前置处理完成后就会进入本阶段。 InitializingBean接口只有一个函数:afterPropertiesSet()这一阶段也可以在bean正式构造完成前增加我们自定义的逻辑,但它与前置处理不同,由于该函数并不会把当前bean对象传进来,因此在这一步没办法处理对象本身,只能增加一些额外的逻辑。 若要使用它,我们需要让bean实现该接口,并把要增加的逻辑写在该函数中。然后Spring会在前置处理完成后检测当前bean是否实现了该接口,并执行afterPropertiesSet函数。当然,Spring为了降低对客户代码的侵入性,给bean的配置提供了init-method属性,该属性指定了在这一阶段需要执行的函数名。Spring便会在初始化阶段执行我们设置的函数。
-
postProcessAfterInitialzation( Object bean, String beanName ) 当前正在初始化的bean对象会被传递进来,我们就可以对这个bean作任何处理。 这个函数会在InitialzationBean完成后执行,因此称为后置处理。
AbstractAutowireCapableBeanFactory.invokeInitMethods()实现了InitializingBean的afterPropertiesSet()方法和init-methodprotected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable { //判断该bean是否实现了实现了InitializingBean接口,如果实现了InitializingBean接口,则只掉调用bean的afterPropertiesSet方法 boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { //直接调用afterPropertiesSet ((InitializingBean) bean).afterPropertiesSet(); return null; } },getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { //直接调用afterPropertiesSet ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null) { String initMethodName = mbd.getInitMethodName(); //判断是否指定了init-method方法,如果指定了init-method方法,则再调用制定的init-method if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { //通过反射调用init-method invokeCustomInitMethod(beanName, bean, mbd); } }
}
-
DisposableBean和destroy-method和init-method一样,通过给destroy-method指定函数,就可以在bean销毁前执行指定的逻辑。
Thx。
ClassPathXmlApplicationContext解析
当我们在启动一个Spring项目的时候,会调用AbstractApplicationContext refresh 方法。refresh的时候会做很多事情:比如完成配置类的解析、各种BeanFactoryPostProcessor和BeanPostProcessor的注册、国际化配置的初始化、web内置容器的构造等等。
@Override
public void refresh() throws BeansException, IllegalStateException {
// refresh过程只能一个线程处理,不允许并发执行
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//1.记录开始时间,验证所需要的配置,环境变量等等。
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//2.完成了配置文件的加载、解析、注册。创建DefaultListableBeanFactory生成BeanReader,BeanDefiniton对象
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//3.配置标准上下文环境。忽略Spring注入接口,如EnvironmentAware等,注册系统环境变量单例Bean等。
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//4.子类覆盖方法做额外的处理。
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//5.激活各种BeanFactory处理器,依次序调用方法,完成BeanFactory的初始化。
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//6.注册拦截bean创建的bean处理器,这里只是注册,真正调用的是在getBean的时候。
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//7.为上下文初始化Message源,即对不同语言的消息体进行国际化处理
initMessageSource();
// Initialize event multicaster for this context.
//8.初始化应用消息广播器,并放入“ApplicationEventMulticaster”bean中
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//9.留给子类来初始化其他的bean
onRefresh();
// Check for listener beans and register them.
//10.在所有注册的bean中查找Listener bean,注册到消息广播器中
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//11.初始化剩下的单实例( 非lazy-init)
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//12.发布refreshEvent事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
2.obtainFreshBeanFactory里面主要方法是refreshBeanFactory。这个方法做了2件事,首先通过refreshBeanFactory()方法,创建了DefaultListableBeanFactory的实例,并进行初始化。
/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//配置是否允许Bean覆盖,Bean是否可以循环引用
customizeBeanFactory(beanFactory);
//加载BeanDefinition
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
loadBeanDefinitions 会调用AbstractXmlApplicationContext的方法
告诉内部bean工厂使用上下文的类装入器等。
上下文回调配置bean工厂。
BeanFactory接口未登记为普通工厂的解析式。MessageSource登记(为自动装配创建)作为一个Bean
如果创建;就去寻找LoadTimeWeaver,然后准备组织
注册默认环境bean。
/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
3.准备BeanFactory排除部分Spring特殊支持的注入接口。并准备系统配置文件等
/**
* Configure the factory's standard context characteristics,
* such as the context's ClassLoader and post-processors.
* @param beanFactory the BeanFactory to configure
*/
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
5.invokeBeanFactoryPostProcessors主要是调用了PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors,并在里面注册了处理器,并按顺序调用了invokeBeanFactoryPostProcessors的
/**
* Instantiate and invoke all registered BeanFactoryPostProcessor beans,
* respecting explicit order if given.
* <p>Must be called before singleton instantiation.
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
11.finishBeanFactoryInitialization主要初始化了单例非lazy-init的实例
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 有容器转换服务bean时先实例化这种Bean
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// 实例化LoadTimeWeaverAware类型Bean
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// 停止使用临时类加载器
beanFactory.setTempClassLoader(null);
// 缓存容器中所有注册的BeanDefinition元数据,以防被修改
beanFactory.freezeConfiguration();
// 实例化剩余的所有非lazy-init singleton Bean
beanFactory.preInstantiateSingletons();
}
AliasRegistry:定义针对alias的简单增删改等操作。
SimpleAliasRegistry:主要使用map作为alias的缓存,是对AliasRegistry的实现。
SingletonBeanRegistry:定义对单例的注册和获取。接口。
BeanFactory:定义获取bean及bean的各种属性。
DefaultSingletonBeanRegistry:实现SingletonBeanRegistry。
HierarchicalBeanFactory:继承BeanFactory,也是在BeanFactory的基础上增加了
parentFactory的支持。
BeanDefinitionRegistry:针对BeanDefinition的各种增删改查操作。
FactoryBeanRegistrySupport:在DefaultSingletonBeanRegistry的基础上增加了对
BeanFactory的特殊处理功能。
ConfigurableBeanFactory:提供配置Factory的各种方法。
ListableBeanFactory:根据各种条件获取Bean的配置清单
AbstractBeanFactory:综合FactoryBeanRegistrySupport和ConfigurableBeanFactory的
功能。
AutowireCapableBeanFactory:提供创建bean、自动注入、初始化、以及应用bean的后
处理器。
AbstractAutowireCapableBeanFactory:综合AbstractBeanFactory和
AutowireCapableBeanFactory进行实现。
ConfigurableListableBeanFactory:BeanFactory的配置清单,指定忽略类型和接口等。
DefaultListableBeanFactory:综合上面所有的功能,主要是对bean注册后的处理。
Maven
Maven
compile (编译范围)
compile是默认的范围;如果没有提供一个范围,那该依赖的范围就是编译范围。编译范围依赖在所有的classpath 中可用,同时它们也会被打包。
provided (已提供范围)
provided 依赖只有在当JDK 或者一个容器已提供该依赖之后才使用。例如, 如果你开发了一个web 应用,你可能在编译 classpath 中需要可用的Servlet API 来编译一个servlet,但是你不会想要在打包好的WAR 中包含这个Servlet API;这个Servlet API JAR 由你的应用服务器或者servlet 容器提供。已提供范围的依赖在编译classpath (不是运行时)可用。它们不是传递性的,也不会被打包。
runtime (运行时范围)
runtime 依赖在运行和测试系统的时候需要,但在编译的时候不需要。比如,你可能在编译的时候只需要JDBC API JAR,而只有在运行的时候才需要JDBC
驱动实现。
test (测试范围)
test范围依赖 在一般的编译和运行时都不需要,它们只有在测试编译和测试运行阶段可用。
system (系统范围)
system范围依赖与provided 类似,但是你必须显式的提供一个对于本地系统中JAR 文件的路径。这么做是为了允许基于本地对象编译,而这些对象是系统类库的一部分。这样的构件应该是一直可用的,Maven 也不会在仓库中去寻找它。如果你将一个依赖范围设置成系统范围,你必须同时提供一个 systemPath 元素。注意该范围是不推荐使用的(你应该一直尽量去从公共或定制的 Maven 仓库中引用依赖)。
Maven的生命周期
maven有三套生命周期,分别为:
1、clean 周期:主要用于清理上一次构建产生的文件,可以理解为删除target目录
2、默认周期,
主要阶段包含:
process-resources 默认处理src/test/resources/下的文件,将其输出到测试的classpath目录中,
compile 编译src/main/java下的java文件,产生对应的class,
process-test-resources 默认处理src/test/resources/下的文件,将其输出到测试的classpath目录中,
test-compile 编译src/test/java下的java文件,产生对应的class,
test 运行测试用例,
package 打包构件,即生成对应的jar, war等,
install将构件部署到本地仓库,
deploy 部署构件到远程仓库
3、site周期
主要阶段包含
site 产生项目的站点文档
site-deploy 将项目的站点文档部署到服务器
Https
Https
HTTPS简介
HTTPS其实是有两部分组成:HTTP + SSL / TLS,也就是在HTTP上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会通过TLS进行加密,所以传输的数据都是加密后的数据。具体是如何进行加密,解密,验证的,且看下图。
-
客户端发起HTTPS请求
这个没什么好说的,就是用户在浏览器里输入一个https网址,然后连接到server的443端口。 -
服务端的配置
采用HTTPS协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请。区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面(startssl就是个不错的选择,有1年的免费服务)。这套证书其实就是一对公钥和私钥。如果对公钥和私钥不太理解,可以想象成一把钥匙和一个锁头,只是全世界只有你一个人有这把钥匙,你可以把锁头给别人,别人可以用这个锁把重要的东西锁起来,然后发给你,因为只有你一个人有这把钥匙,所以只有你才能看到被这把锁锁起来的东西。 -
传送证书
这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间等等。 -
客户端解析证书
这部分工作是有客户端的TLS来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随即值。然后用证书对该随机值进行加密。就好像上面说的,把随机值用锁头锁起来,这样除非有钥匙,不然看不到被锁住的内容。 -
传送加密信息
这部分传送的是用证书加密后的随机值,目的就是让服务端得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。 -
服务段解密信息
服务端用私钥解密后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对称加密。所谓对称加密就是,将信息和私钥通过某种算法混合在一起,这样除非知道私钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全。 -
传输加密后的信息
这部分信息是服务段用私钥加密后的信息,可以在客户端被还原 -
客户端解密信息
客户端用之前生成的私钥解密服务段传过来的信息,于是获取了解密后的内容。整个过程第三方即使监听到了数据,也束手无策。
SL介于应用层和TCP层之间。应用层数据不再直接传递给传输层,而是传递给SSL层,SSL层对从应用层收到的数据进行加密,并增加自己的SSL头。
题外
为什么fiddler,wireshark可以抓包https。
当客户端完成请求并解密后才被代理。
搜索推荐
fiddler 修改响应
中间人攻击
https://segmentfault.com/a/1190000011675421
Java面试通关要点汇总集
简历篇
请自我介绍
请介绍项目
基础篇
基本功
面向对象的特征
final, finally, finalize 的区别
int 和 Integer 有什么区别
重载和重写的区别
抽象类和接口有什么区别
说说反射的用途及实现
说说自定义注解的场景及实现
HTTP 请求的 GET 与 POST 方式的区别
session 与 cookie 区别
session 分布式处理
JDBC 流程
MVC 设计**
equals 与 == 的区别
集合
List 和 Set 区别
List 和 Map 区别
Arraylist 与 LinkedList 区别
ArrayList 与 Vector 区别
HashMap 和 Hashtable 的区别
HashSet 和 HashMap 区别
HashMap 和 ConcurrentHashMap 的区别
HashMap 的工作原理及代码实现
ConcurrentHashMap 的工作原理及代码实现
线程
创建线程的方式及实现
sleep() 、join()、yield()有什么区别
说说 CountDownLatch 原理
说说 CyclicBarrier 原理
说说 Semaphore 原理
说说 Exchanger 原理
说说 CountDownLatch 与 CyclicBarrier 区别
ThreadLocal 原理分析
讲讲线程池的实现原理
线程池的几种方式与使用场景
线程的生命周期
锁机制
说说线程安全问题
volatile 实现原理
synchronize 实现原理
synchronized 与 lock 的区别
CAS 乐观锁
ABA 问题
乐观锁的业务场景及实现方式
核心篇
数据存储
MySQL 索引使用的注意事项
说说反模式设计
说说分库与分表设计
分库与分表带来的分布式困境与应对之策
说说 SQL 优化之道
MySQL 遇到的死锁问题
存储引擎的 InnoDB 与 MyISAM
数据库索引的原理
为什么要用 B-tree
聚集索引与非聚集索引的区别
limit 20000 加载很慢怎么解决
选择合适的分布式主键方案
选择合适的数据存储方案
ObjectId 规则
聊聊 MongoDB 使用场景
倒排索引
聊聊 ElasticSearch 使用场景
缓存使用
Redis 有哪些类型
Redis 内部结构
Redis 内存淘汰机制
聊聊 Redis 使用场景
Redis 持久化机制
Redis 集群方案与实现
Redis 为什么是单线程的
缓存崩溃
缓存降级
使用缓存的合理性问题
消息队列
消息队列的使用场景
消息的重发补偿解决思路
消息的幂等性解决思路(已解答,待补充)
消息的堆积解决思路
自己如何实现消息队列
如何保证消息的有序性
框架篇
Spring
BeanFactory 和 ApplicationContext 有什么区别
Spring Bean 的生命周期
Spring IOC 如何实现
说说 Spring AOP
Spring AOP 实现原理
动态代理(cglib 与 JDK)
Spring 事务实现方式
Spring 事务底层原理
如何自定义注解实现功能
Spring MVC 运行流程
Spring MVC 启动流程
Spring 的单例实现原理
Spring 框架中用到了哪些设计模式
Spring 其他产品(Srping Boot、Spring Cloud、Spring Secuirity、Spring Data、Spring AMQP 等)
Netty
为什么选择 Netty
说说业务中,Netty 的使用场景
原生的 NIO 在 JDK 1.7 版本存在 epoll bug
什么是TCP 粘包/拆包
TCP粘包/拆包的解决办法
Netty 线程模型
说说 Netty 的零拷贝
Netty 内部执行流程
Netty 重连实现
微服务篇
微服务
前后端分离是如何做的
如何解决跨域
微服务哪些框架
你怎么理解 RPC 框架
说说 RPC 的实现原理
说说 Dubbo 的实现原理
你怎么理解 RESTful
说说如何设计一个良好的 API
如何理解 RESTful API 的幂等性
如何保证接口的幂等性
说说 CAP 定理、 BASE 理论
怎么考虑数据一致性问题
说说最终一致性的实现方案
你怎么看待微服务
微服务与 SOA 的区别
如何拆分服务
微服务如何进行数据库管理
如何应对微服务的链式调用异常
对于快速追踪与定位问题
微服务的安全
分布式
谈谈业务中使用分布式的场景
Session 分布式方案
分布式锁的场景
分布是锁的实现方案
分布式事务
集群与负载均衡的算法与实现
说说分库与分表设计
分库与分表带来的分布式困境与应对之策
安全问题
安全要素与 STRIDE 威胁
防范常见的 Web 攻击
服务端通信安全攻防
HTTPS 原理剖析
HTTPS 降级攻击
授权与认证
基于角色的访问控制
基于数据的访问控制
性能优化
性能指标有哪些
如何发现性能瓶颈
性能调优的常见手段
说说你在项目中如何进行性能调优
工程篇
需求分析
你如何对需求原型进行理解和拆分
说说你对功能性需求的理解
说说你对非功能性需求的理解
你针对产品提出哪些交互和改进意见
你如何理解用户痛点
设计能力
说说你在项目中使用过的 UML 图
你如何考虑组件化
你如何考虑服务化
你如何进行领域建模
你如何划分领域边界
说说你项目中的领域建模
说说概要设计
设计模式
你项目中有使用哪些设计模式
说说常用开源框架中设计模式使用分析
说说你对设计原则的理解
23种设计模式的设计理念
设计模式之间的异同,例如策略模式与状态模式的区别
设计模式之间的结合,例如策略模式+简单工厂模式的实践
设计模式的性能,例如单例模式哪种性能更好。
业务工程
你系统中的前后端分离是如何做的
说说你的开发流程
你和团队是如何沟通的
你如何进行代码评审
说说你对技术与业务的理解
说说你在项目中经常遇到的 Exception
说说你在项目中遇到感觉最难Bug,怎么解决的
说说你在项目中遇到印象最深困难,怎么解决的
你觉得你们项目还有哪些不足的地方
你是否遇到过 CPU 100% ,如何排查与解决
你是否遇到过 内存 OOM ,如何排查与解决
说说你对敏捷开发的实践
说说你对开发运维的实践
介绍下工作中的一个对自己最有价值的项目,以及在这个过程中的角色
软实力
说说你的亮点
说说你最近在看什么书
说说你觉得最有意义的技术书籍
说说个人发展方向方面的思考
说说你认为的服务端开发工程师应该具备哪些能力
说说你认为的架构师是什么样的,架构师主要做什么
说说你所理解的技术专家
HR 篇
你为什么离开之前的公司
你为什么要进我们公司
说说职业规划
你如何看待加班问题
谈一谈你的一次失败经历
你觉得你最大的优点是什么
你觉得你最大的缺点是什么
你在工作之余做什么事情
你为什么认为你适合这个职位
你觉得自己那方面能力最急需提高
你来我们公司最希望得到什么
你希望从这份工作中获得什么
你对现在应聘的职位有什么了解
您还有什么想问的
你怎么看待自己的职涯
谈谈你的家庭情况
你有什么业余爱好
你计划在公司工作多久
分布式理论
分布式理论
CAP原则(CAP定理)
CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
CAP原则是NOSQL数据库的基石。Consistency(一致性)。 Availability(可用性)。Partition tolerance(分区容错性)。
分布式系统的CAP理论:理论首先把分布式系统中的三个特性进行了如下归纳:
一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
分区容忍性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
BASE理论
BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的简写,BASE是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的结论,是基于CAP定理逐步演化而来的,其核心**是即使无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。
延伸
BASE(Basically Available, Soft State, Eventual Consistency 基本可用、软状态、最终一致性) 对CAP AP理论的延伸, Redis等众多系统构建与这个理论之上
ACID 传统数据库常用的设计理念, ACID和BASE代表了两种截然相反的设计哲学,分处一致性-可用性分布图谱的两极。
2PC
2PC(tow phase commit)两阶段提交[5]顾名思义它分成两个阶段,先由一方进行提议(propose)并收集其他节点的反馈(vote),再根据反馈决定提交(commit)或中止(abort)事务。我们将提议的节点称为协调者(coordinator),其他参与决议节点称为参与者(participants, 或cohorts):
3PC
相比2PC,3PC增加了一个准备提交(prepare to commit)阶段来解决以上问题:
coordinator接收完participant的反馈(vote)之后,进入阶段2,给各个participant发送准备提交(prepare to commit)指令。participant接到准备提交指令后可以锁资源,但要求相关操作必须可回滚。coordinator接收完确认(ACK)后进入阶段3、进行commit/abort,3PC的阶段3与2PC的阶段2无异。协调者备份(coordinator watchdog)、状态记录(logging)同样应用在3PC。
文章推荐
https://www.roncoo.com/course/view/7ae3d7eddc4742f78b0548aa8bd9ccdb#boxTwo
http://p.primeton.com/articles/59030eeda6f2a40690f03602
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.