Bootstrap

Spring源码解析 -- Spring bean的生命周期在何时完成依赖注入

详细的大家可以看https://blog.csdn.net/java_lyvee/article/details/101793774或者它的bilibili视频

bean的创建过程:

在这里插入图片描述

  1. spring扫描scan指定的包下添加了Component等注解的类
  2. 为这些类创建一个BeanDefinition的子类对象,这个子类对象包含这个类的一些基本信息如类名称、描述、构造器参数、是否需要延迟加载等等
    在这里插入图片描述
  3. 将这个子类对象放到Spring的单例池(是一个map)中,
    在这里插入图片描述
  4. 如果我们需要对spring进行扩展,可以让类实现BeanFactoryPostProcessor接口,如果实现了此接口,我们会在创建子类对象存放到map之后,new对象之前,会去调用扩展的方法。
    比如原来的BeanDefinition子类对象中有一个属性时beanClass,这个beanClass存放的是x这个类,我们可以在此时将x换成Y,因为Y我们没有添加到包扫描中,这样我们创建出的就是Y的对象。

在这里插入图片描述

  1. 最近通过for循环获取BeanDefinition子类对象的构成的map中的子类对象,查看这个类的基本信息,进行验证,如果需要创建对象,就调用prestantiateSingletons将此类new出来,放到Spring单例池中。
    源码验证过程的一部分小示例:(DefaultListableBeanFactory类中)
 RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
                if (!mbd.isAbstract() && (allowEagerInit || (mbd.hasBeanClass() || !mbd.isLazyInit() || this.isAllowEagerClassLoading()) && !this.requiresEagerInitForType(mbd.getFactoryBeanName()))) {
                    

在这里插入图片描述
在这里插入图片描述

spring对类进行扩展举例:

  1. 添加了Component注解的类:
@Component
public class UserServiceA {
    public UserServiceA() {
        System.out.println("A init ....");
    }
}
  1. 没有添加注解的类:
public class UserServiceB {
    public UserServiceB() {
        System.out.println("B init ....");
    }
}
  1. 包扫描类:
@ComponentScan("com.yhx.toali.SpringStudy")
public class ScanConfig {
}
  1. spring扩展类,将注入的UserSerivceA对象替换为UserServiceB对象:
@Component
public class ExtendSpring implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        GenericBeanDefinition userServiceA = (GenericBeanDefinition) configurableListableBeanFactory.getBeanDefinition("userServiceA");
        // 将注入的UserSerivceA对象替换为UserServiceB对象
        userServiceA.setBeanClass(UserServiceB.class);
    }
}
  1. 测试类:
public class GetBean {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac =
                new AnnotationConfigApplicationContext(ScanConfig.class);
        System.out.println(ac.getBean(UserServiceB.class));
    }
}
  1. 输出结果:
    在这里插入图片描述

问题:如何证明Spring是默认支持循环依赖的?

Spring在初始化bean的生命周期过程当中,当它把bean实例化之后,他会去进行一次判断,判断容器允不允许循环依赖,判断的属性是allowCircularReferences,这个属性默认是true,我们可以通过spring提供的api来设置这个属性。 如果这次判断成立,spring会去第四次调用后置处理器。

示例:关闭循环依赖

/*AnnotationConfigApplicationContext ac =
                new AnnotationConfigApplicationContext(ScanConfig.class);*/
        AnnotationConfigApplicationContext ac =
                new AnnotationConfigApplicationContext();
        ac.register(ScanConfig.class);
        
        AbstractAutowireCapableBeanFactory beanFactory =
                (AbstractAutowireCapableBeanFactory) ac.getBeanFactory();
        // 关闭循环依赖
        beanFactory.setAllowCircularReferences(false);
        
        // 这个方法才是真正的初始化bean的方法,所以我们可以在这个方法调用之前,关闭循环依赖
        ac.refresh();

问题:@Resource和@Autowired的区别

  1. 简单区别:Autowired支持类型注入,Resource支持类型和类名注入
  2. 深入区别:他们后置处理器的处理类不一样,CommonAnnotationBeanPostProcessor是处理Resource的,AutowiredAnnotationBeanPostProcessor是处理Autowired的。

循环依赖的解决过程(理论):

假设A中注入了B,B中注入了A。

  1. 第一次实例化A时,Spring会调用doGetBeam去容器中拿A,如果拿不到A,再判断A是不是在创建的过程中,如果也不在创建的过程中,会调用getSingleton方法创建A,在创建A之前,会调用beforeSingletonCreation(beanName)方法把A放到一个set集合中,表示A正在创建。如果下次再调用getSingleton方法,进入判断A是不是创建中的状态,就会判断为true。
    doGetBean方法:
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
    String beanName = this.transformedBeanName(name);
    // 调用getSingleton判断容器中有没有或者该bean有没有再创建的过程中
    Object sharedInstance = this.getSingleton(beanName);

	........
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "Bean name must not be null");
        synchronized(this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                if (this.singletonsCurrentlyInDestruction) {
                    throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)");
                }

                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
                }
				// 标记为创建中
                this.beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = this.suppressedExceptions == null;
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet();
                }
                。。。。
protected void beforeSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }
}

private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap(16));
  1. 接着调用createbean方法把A创建出来(instanceWrapper = this.createBeanInstance(beanName, mbd, args);),调用构造方法,然后走A的生命周期,当生命周期走到populateBean()这个方法时,Spring会去填充A中的属性(注入),发现B需要填充,然后Spring就去getBean(B),但是此时spring容器中并没有B,因为此时只实例化了A对象。(对象并不是bean,只能是一个bean的半成品)
.....

if (mbd.isSingleton()) {
   sharedInstance = this.getSingleton(beanName, () -> {
        try {
        	// createBean调用AbstractAutowireCapableBeanFactory类中的createBean发方法
        	// 解咒调用doCreateBean方法
            return this.createBean(beanName, mbd, args);
        } catch (BeansException var5) {
            this.destroySingleton(beanName);
            throw var5;
        }
    });
    bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} 

....
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }

        if (instanceWrapper == null) {
        	// 创建对象 new的过程
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }

        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        synchronized(mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } catch (Throwable var17) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
                }

                mbd.postProcessed = true;
            }
        }

		// 判断是否允许循环依赖
        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }
			// 第四次调用后置处理器,把bean工厂放到一个以beanname为key的map工厂(第二个map)中
            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }

        Object exposedObject = bean;

        try {
        	// 填充当前类的属性
            this.populateBean(beanName, mbd, instanceWrapper);
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }

            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = this.getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                } else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
                    String[] dependentBeans = this.getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
                    String[] var12 = dependentBeans;
                    int var13 = dependentBeans.length;

                    for(int var14 = 0; var14 < var13; ++var14) {
                        String dependentBean = var12[var14];
                        if (!this.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.");
                    }
                }
            }
        }

        try {
            this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
            return exposedObject;
        } catch (BeanDefinitionValidationException var16) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
        }
    }
  1. 此时又去实例化B(和A一样的步骤),创建B,调用构造方法,然后走B的生命周期,当生命周期走到populateBean()这个方法时,Spring又去填充B中的属性,发现A需要填充,又去容器中getBean(A),但是此时容器中并没有A的Bean,此时new出来的只是对象并不是Bean 。
  2. 因为每次getBean,都会先去去Spring单例池中拿,如果单例池中拿不到,再去判断对象是不是再创建的过程中,如果对象在创建的过程中,此时就从第三个缓存(earlySingletonObjects)中拿A,但是之前是将A的bean工厂放到第二个缓存中(singletonFactories),所以目前从第三个缓存拿不到A,接着进入判断,判断为true,从第二个缓存中拿到bean放到第三个缓存中,从第二个缓存中清除
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	// singletonObjects --> 第一个map:单例池(Spring容器)
    Object singletonObject = this.singletonObjects.get(beanName);
    // 单例对象此时为空,接着判断对象是不是在创建的过程中 
    if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
        synchronized(this.singletonObjects) {
        	// earlySingletonObjects --> 第三个map:第三个缓存
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
            	//singletonFactories --> 第二个map:工厂map
                ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                	// 从第二个map(缓存)中拿到bean的半成品
                    singletonObject = singletonFactory.getObject();
                    // 放到第三个缓存中
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    // 从第二个缓存中删除
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }

    return singletonObject;
}
  1. 此时A是个半成品,然后将A填充到B中,B填充完成,成为了一个完整的Bean。
  2. 接着,方法会不停往前返回,一直到A填充B的地方,B此时已经有了,此时会将B填充上,整个流程基本完成。

上节中的三个map(缓存)

1.三级缓存: Map<String, Object> earlySingletonObjects = new HashMap(16);

三级缓存put了一个从二级缓存中产生出来的一个对象。防止二级缓存每次都产生对象

为什么不直接从二级缓存拿(不要三级缓存,只用原来的二级缓存工厂)?

因为性能问题,如果只用原来的二级缓存工厂,我们可能有多个循环引用比如A
,B中都引用C,如果我们只使用二级缓存,如果每次二级缓存创建都需要10s,第二次可能还是要10s,如果第一次创建完就放到三级缓存中可以节省时间提高性能。

2.二级缓存:Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);

里面放的是对象的工厂对象 ,为了解决循环依赖。(利用了策略+工厂模式生成了一个合格的Bean)
为什么要存放工厂对象,为了进行AOP,对bean进行升级处理。
对象进入工厂之后,想干嘛就干嘛,可以产生你想要的自定义的代理对象,对对象进行加工。
比如循环依赖时,A中有B,B中有A,先创建A,A要注入B,B要注入A,并且B觉得A的功能不够用,此时A的工厂对象在二级缓存中,我们获取到A注入到B中,获取到的A并不是A本身,而是A的代理对象,加工之后的A 。

1.一级缓存: Map<String, Object> singletonObjects = new ConcurrentHashMap(256);

beanName为key,单例bean为value
一级缓存,其实就是spring单例池,即Spring容器。
单例对象只会初始化一次,所以需要一个单例池来缓存。
原形就不需要缓存。

Bean生命周期回调

分为2种:

  1. 初始化回调
  2. 销毁回调

初始化回调三种方式:

  1. 实现InitializingBean接口,重写其中afterPropertiesSet()方法
  2. 在类中定义一个方法,在xml中配置init-method
  3. 在bean的随便一个方法上加上@PostConstruct注解

初始化回调三种方法可以同时存在,这三种方法的执行顺序:
先执行注解方式,再执行实现接口方法,最后执行xml方式。

原因:

if (mbd == null || !mbd.isSynthetic()) {
	// 执行spring中的内置处理器,@PostConstruct
    wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
}

try {
	// 执行InitializingBean 初始化
	// 这里时解析接口和xml方式的
    this.invokeInitMethods(beanName, wrappedBean, mbd);
}

Spring中的策略模式

比如BeanPostProcessor接口,被很多类实现,每个类对同一个方法有不同的实现。

Spring在Bean的生命周期中,会调用BeanPostProcessor这个后置处理器,内部就是用策略模式,所有的后置处理器都实现了BeanPostProcessor接口,每个后置处理器对BeanPostProcessor接口中的方法都有不同的实现,有的对Bean进行了修改,有的进行了方法调用,得到Bean的所有注解信息等等。

;