在doGetBean方法当中,处理完bename之后,下一步就是尝试从单例池中获取。如果能获取到,那么就对其进行FactoryBean的处理。当然这个处理对于FactoryBean才有用,对应代码如下:
// Eagerly check singleton cache for manually registered singletons.
//如果这里是我们的bean,那么第一次获取肯定是空的,那么这个时候就会走else
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//2.完成FactoryBean的相关处理,并用来获取FactoryBean的处理结果。
//缓存中的bean记录的是最原始的Bean状态,我们得到的不一定是最终想要的bean
//
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
//传入的第二个参数就是指是否允许延迟加载
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//第一次调用getSongleton,返回肯定为空
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//从三级缓存拿,如果是第一次坑定是拿不到的
singletonObject = this.earlySingletonObjects.get(beanName);
//如果从三级缓存中拿不到,那么判断是否支持循环依赖,再从二级缓存中拿
/**
* 为什么不直接从二级缓存中拿,而是要put到三级缓存中呢
* 性能问题:因为二级缓存是一个工厂,代码相当复杂。从二级缓存中创建出对象的时候进行大量的操作
* 为了避免每次引用这个对象都要使用工厂来创建,就需要使用到三级缓存。
* 既然有性能消耗,那么为什么还要使用工厂呢?
* 解答:因为在前面说过spring的生命周期:
* 1.new
* 2.注入
* 3.执行生命周期方法
* 4.AOP代理
* 5.放入单例池
* 还是循环依赖的场景。如果此时A到了注入的那一步,那么就会进入到B的生命周期。如果这个地方我们不使用工厂
* 那么在B中注入的A就是只执行到第二步的一个A的对象。B的A就不是AOP代理过后的对象。为了解决这个问题使用工厂,因为
* 它可以使这个A的AOP操作提前到这个工厂中来执行。所以说这个工厂的代码也是极其复杂的。为了避免重复执行这里面
* 的代码,这里也用到了三级缓存的。
*/
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//从二级缓存中拿到了
singletonObject = singletonFactory.getObject();
//将其放到三级缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
//将二级缓存中的清除掉
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
这里面有一些注释是针对解决循环引用的问题来说嘚。
大致流程如下:首先直接到单例池中拿,如果没有,到三级缓存中拿,如果还拿不到,再到二级缓存中拿,拿到了之后最后要放入三级缓存,然后删除二级缓存中的。为什么要去二三级缓存这样的名字不重要。来看看这些单例池和缓存都是什么东西:
/**单例池 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 三级缓存,这里的bean还只是一个对象,还没成为真正的bean beanname-->实例 */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** beanname到能创建这个bean对象的工厂的映射 为什么是工厂之后再说*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
三级缓存是解决循环依赖的关键。如果是bean才刚刚开始创建,那么肯定获取不到。
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
/** 正在创建的bean的名字的集合 */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
spring在解决循环依赖的时候,会将没有完成生命周期的bean放入到这个map中,然后通过isSingletonCurrentlyInCreation来判断是否是在创建之中。这个也是解决循环依赖的关键代码。
到这里bean就已经获取了,根据上面的代码,如果获取到了要调用getObjectForBeanInstance方法,进行FactoryBean的处理。这个方法的主要逻辑就是将一个获取到的Bean实例传入,如果它不是FactoryBean,那么就会返回它自己,如果是,那么就返回FactoryBean创建的实例。
为了方便理解,先给出这个方法的时序图:
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
//1.若为工厂引用(name的开头是&)
if (BeanFactoryUtils.isFactoryDereference(name)) {
//如果name以&开头,//如果是nullBean直接返回
// if (beanInstance instanceof NullBean) {
// return beanInstance;
// }却又不是FactoryBean直接抛出异常。
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
// 到这里我们就有了一个 Bean 实例,当然该实例可能是会是是一个正常的 bean 又或者是一个 FactoryBean
// 如果是 FactoryBean,我我们则创建该 Bean,除非调用者需要的正是一个FactoryBean
//这里在干嘛啊??????这个地方难道不是矛盾的吗
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
//3.若传入的BeanDefinition为null,就从缓存中加载Bean对象。
//getCachedObjectForFactoryBean从一个map当中,通过beanName获取FactoryBean
//这个缓存中保存了从factory中可以获取到的bean
//这里的object获取到了就直接是最后需要的bean了
object = getCachedObjectForFactoryBean(beanName);
}
// 若 object 依然为空,则可以确认,beanInstance 一定是 FactoryBean 。从而,使用 FactoryBean 获得 Bean 对象
//因为缓存池中取不到
if (object == null) {
// 进行类型转换
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
//containsBeanDefinition方法检查beanName是否在beanDefinitionMap 中,这个map中
//保存所有已经加载的类。
//这个if是肯定会被满足的
if (mbd == null && containsBeanDefinition(beanName)) {
// 将存储 XML 配置文件的 GenericBeanDefinition 转换为 RootBeanDefinition,
// 如果指定 BeanName 是子 Bean 的话同时会合并父类的相关属性
mbd = getMergedLocalBeanDefinition(beanName);
}
//判断是否是用户定义的,而不是应用程序本身定义的。
//mbd.isSynthetic()判断是否为用户定义的
//但是这里传入的mbd就null直接为false
//下面传入的!synthetic就为true
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 核心处理方法,使用 FactoryBean 获得 Bean 对象
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
开头进行一堆判断,如果它是一个factorybean的话,最后会调用getObjectFromFactoryBean方法来执行从,factorybean中加载bean的逻辑。
beanInstance
。beanInstance
) 中,获取 Bean 实例对象。protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
//1.为单例模式且在缓存中存在
//containsSingleton直接到单例池中查看有没有
if (factory.isSingleton() && containsSingleton(beanName)) {
//互斥锁加锁
synchronized (getSingletonMutex()) {
//1.2从缓存中获取指定的factoryBean
Object object = this.factoryBeanObjectCache.get(beanName);
//如果为空,就从FactoryBean中获取对象
//如果是第一次获取应该是获取不到的
if (object == null) {
//调用doGetObjectFromFactoryBean方法来获取bean
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
//1.3需要后续处理。shouldPostProcess为true,所以这里的代码会执行
if (shouldPostProcess) {
//若bean处于创建中,就返回非处理对象,而不是存储它
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
//单例Bean的前置处理
//会往singletonsCurrentlyInCreation中加入beanName
beforeSingletonCreation(beanName);
try {
//对从FactoryBean获取的对象进行后处理
//生成的对象将暴露给bean引用
//这个方法的实现在这里啥也没干,需要自己扩展
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
//单例Bean的后置处理
//就是beforeSingletonCreation的反操作
afterSingletonCreation(beanName);
}
}
//1.4添加到factoryBeanObject中进行缓存。
//在这里加进去的
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
//到这里说明单例池中是没有这个beanName的
else {
//为空就从FactoryBean中加载对象
Object object = doGetObjectFromFactoryBean(factory, beanName);
//需要后续处理
if (shouldPostProcess) {
try {
// 对从 FactoryBean 获取的对象进行后处理
// 生成的对象将暴露给 bean 引用
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
该方法进来就会判断这个FactoryBean是否在单例池中包含着。那么什么情况不会包含着呢,那就是解决循环依赖的时候,该FactoryBean会处在创建中,而没有被单例池包括(不知道对不对,我是这样理解的)
对单例池加锁,可以在Spring的IOC容器里看到很多对单例池加锁的代码,IOC容器要保证单例池全局唯一,所以对单例池加互斥锁。
如果单例池中包含了,首先还是先检查缓存,缓存中检查不到,就调用doGetObjectFromFactoryBean方法,在这个方法中直接调用factory的getObject()方法来获取bean,这里就不展开讲了,然后分别会调用
beforeSingletonCreation(beanName);postProcessObjectFromFactoryBean(object, beanName);以及afterSingletonCreation(beanName);具体作用看注释。
如果单例池中获取不到,就不需要对单例池进行加锁。执行的逻辑也是差不多的。
最后如果这个FactoryBean已经进入了单例池,那么会调用this.factoryBeanObjectCache.put(beanName, object);将bean放入到缓存,方便下次获取。
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
//需要权限验证
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
//从FactoryBean中获取Bean对象
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//从FactoryBean中获取Bean对象
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
主要逻辑就是object = factory.getObject();如果通过object = factory.getObject();都没有获取到,那么会构造一个NullBean返回。
这个方法是用于检测bean创建状态的,这个方法之前讲过。
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
再回来看beforeSingletonCreation(beanName);postProcessObjectFromFactoryBean(object, beanName);以及afterSingletonCreation(beanName);三个函数,在getObjectFromFactoryBean方法中被调用。主要作用如下(在注释中也有说明)
beforeSingletonCreation(beanName):将beanname添加到singletonsCurrentlyInCreation这个map中
afterSingletonCreation(beanName):将beanname从singletonsCurrentlyInCreation中移除
postProcessObjectFromFactoryBean(object, beanName): ,对从 FactoryBean 处获取的 Bean 实例对象进行后置处理。其默认实现是直接返回 object 对象,不做任何处理。
// DefaultSingletonBeanRegistry.java
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {
return object;
}
这个方法在这里没有做什么。但是子类可以重写,比如 AbstractAutowireCapableBeanFactory
// AbstractAutowireCapableBeanFactory.java
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
applyBeanPostProcessorsAfterInitialization方法的作用是将当前bean传入到后置处理器中,让后置处理器对其进行处理。之后我们会详细讲解这个方法。
到这里,主要学习了两个知识点,一是spring如何从单例池或者缓存中获取实例。二是获取的实例如果是一个FactoryBean,如何根据这个FactoryBean获取到真正的Bean实例。中间涉及到了很多的细节问题。