读源码的时候可以学习好的设计模式,并实践思考。
Spring有三级缓存:
一级缓存singletonObjects是线程安全的ConcurrentHashMap。
二级缓存是earlySingletonObjects,主要存放半成品的单例bean。
三级缓存singletonFactories核心是解决aop循环依赖。
第三级缓存存放原生的早期对象,二级缓存存放记过代理之后的对象。
代理分为jdk代理和cglib代理,在spring源码的方法里,postProcessBeforeInstantiation方法里,此方法可以在创建bean前返回自己的bean(可以保证单实例)。
getSingleton()方法怎么运行的?
这里面有两个方法需要解释,isSingletonCurrentlyInCreation()判断当前单例bean是否正在创建中,也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象, 或则在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。)
allowEarlyReference 是否允许从singletonFactories中通过getObject拿到对象,先从单一级缓存singletomObjects获取,没有从二级缓存earlySingletonObjects获取,没有的话再从三级缓存singletomFactory获取,当获取到值后,吧获取的实例放入二级缓存,并吧三级缓存singletomFactory里面的值移除。
beanFactory和factoryBean区别?
Spring最大的模式就是工厂模式
他们都是接口,beanFactory是帮spring维护bean的工厂。
而factoryBean是spring提供创建一些复杂的对象,比如Connnection和sqlSessionFactory对象,不能new的对象,需要我们实现factoryBean接口,这个接口里面可以判断是单实例还是多实例,主要是getObject方法来获取对象,然后把这个对象写在配置文件,或者实现配置类,通过获取工厂的getBean(id)来获取这个对象,如果想获取这个实现对象,getBean对象前面加个&来获取。
ApplicationContext是beanFactory的子接口,所以功能比beanFactory接口更强大,负责创建bean并且吧这些单实例bean保存在map中。AOP 的DI注入都是在applicationContext接口下的这些类中。ApplicationContext是留给开发者使用的aop容器接口。
Spring如何解决循环依赖?
protected T doGetBean(final String name, @Nullable final Class requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 尝试通过bean名称获取目标bean对象,比如这里的A对象
Object sharedInstance = getSingleton(beanName);
// 我们这里的目标对象都是单例的
if (mbd.isSingleton()) {
// 这里就尝试创建目标对象,第二个参数传的就是一个ObjectFactory类型的对象,这里是使用Java8的lamada
// 表达式书写的,只要上面的getSingleton()方法返回值为空,则会调用这里的getSingleton()方法来创建
// 目标对象
sharedInstance = getSingleton(beanName, () -> {
try {
// 尝试创建目标对象
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
throw ex;
}
});
}
return (T) bean;
}
从spring源码开始分析:
第一步走的getSingleton先通过对象名字从缓存中获取bean,如果没有获取到,尝试获取半成品的bean,如果这里获取的是null,则进入第二个步骤。
第二步的getSingleton直接尝试创建bean对象,并且实例化之后会通过postProperlateyValue里面的populate赋值,setBeanName和setFactoryName。这里创建会调用三次doCrateBean方法,主干创建bean对象的逻辑。
这时候A对象创建的是半成品,因为依赖B对象,这时候递归调用继续走第二个getSingleton,创建B对象,这时候,B也依赖A,可以从第一个getSingleton获取到刚刚创建的半成品A。
这时候B对象实例化完成,此刻里面有一个依赖的半成品A,这时候再把递归实例化成功的B返回,此时A也依赖成功,A实例化完成。
spring主要就是运动递归的方式获取目标bean和其依赖的bean。
实例化bean分为两步,第一步就是实例化一个bean,第二部注入pouplate属性。首先就是递归实例化所有依赖的bean,直到某个bean没有依赖其他bean,此时就会把实例返回,然后递归将各个实例化完成的bean进行属性赋值。
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 尝试从缓存中获取成品的目标对象,如果存在,则直接返回
Object singletonObject = this.singletonObjects.get(beanName);
// 如果缓存中不存在目标对象,则判断当前对象是否已经处于创建过程中,在前面的讲解中,第一次尝试获取A对象
// 的实例之后,就会将A对象标记为正在创建中,因而最后再尝试获取A对象的时候,这里的if判断就会为true
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 这里的singletonFactories是一个Map,其key是bean的名称,而值是一个ObjectFactory类型的
// 对象,这里对于A和B而言,调用图其getObject()方法返回的就是A和B对象的实例,无论是否是半成品
ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 获取目标对象的实例
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}