[关闭]
@Catyee 2021-06-29T02:42:25.000000Z 字数 20658 阅读 954

源码解析Spring Bean的生命周期

Spring


声明:下文中涉及的Spring源码都是Spring 5.3.7版本

Spring中用的最多的是单例bean,单例bean的创建、使用、销毁都是由Spring容器管理的,对于原型bean,spring只负责创建,在创建结束之后就不会再管了,销毁或释放资源都是要由开发者自己控制,所以我们经常说的"spring bean的生命周期"实际上指的是单例bean的生命周期。对于单例bean和原型bean以外类型的bean,由于使用的场景比较少,这里也不进行讲述。

Spring bean说到底也就是一个java对象,一个java对象的生命周期是什么样子的?首先通过构造器将对象实例化出来,如果构造器实例化的时候没有给属性赋值,在实例化之后还可以通过set方法给属性赋值,这之后就可以使用这个对象,使用完成之后被jvm回收掉。Spring bean也是java对象,所以和java对象一样spring bean的生命周期也离不开实例化 -> 使用 -> 最后销毁的过程,不过Spring作为一个功能全面、强大的框架,可以对bean的生命周期进行更细粒度的控制。除了实例化之外,还可以处理bean的依赖关系(依赖注入);可以对bean进行各种功能增强;也允许用户自定义一些初始化操作;对于单例bean来说,spring会将其保存在容器中,这样暂时使用完的bean不会被垃圾回收,下次使用的时候不需要再创建,而是直接获取。总之,Spring对bean的创建、使用、销毁进行了全面的接管,这也是IoC(控制反转)的具体体现

详细来说我们可以把bean的生命周期分为如下几个阶段:

按照这样的划分我们来看Spring bean完整的生命周期:

一、生成bean的模型对象BeanDefinition

BeanDefinitio即bean的建模器或者bean的定义器,它保存了一个Bean的所有信息,这些信息包括bean的属性、构造方法参数、显示依赖的Bean的名称(即@DependsOn注解中指定的bean名称)、是否单例、是否延迟加载、初始化和销毁方法等各种信息,Spring最终会根据BeanDefinition来创建对象。那BeanDefinition是什么时候创建的呢?

Spring容器在启动的时候会去扫描指定的包,识别出哪些类需要由spring接管,每扫描到一个类会生成一个MetadataReader对象,在这个对象中通过ASM框架(Java字节码操控框架,可以方便的解析出类中的所有元素:类名、方法、属性等,cglib动态代理底层也使用了ASM框架,其性能要远好于java反射)解析class文件,得到类的元数据信息和注解信息,通过这些信息就可以创建BeanDefinition对象了。这里要注意,扫描过程中获取的这些类本身没有进行类加载,所以这个时候jvm中还没有这些类的Class对象。

  1. 思考:
  2. java中类的Class对象已经包含了类的各种信息,为什么还需要有一个专门的BeanDefinition来保存类的信息?
  3. 答案:
  4. Class对象确实保存了一个类的所有信息,但是Spring实例化一个bean需要更多信息,比如是否懒加载,beanscopebean的依赖等等,这些是Class对象无法提供的,所以Spring专门设计了这样一个类来存储定义一个bean所需要的各种信息。

二、创建bean

获取到bean的BeanDefinition之后就可以根据BeanDefinition创建bean了,Spring容器会按照字典序来创建非懒加载的这些Bean。

如果调试过这个创建的步骤,会发现Spring最终会调用到AbstractAutowireCapableBeanFactory类的createBean()方法,createBean()方法又会调用doCreateBean()方法,doCreateBean()还会调用initializeBean()方法,这三个方法执行结束,一个bean就真正意义的创建完成了,所以这三个方法非常重要,从这三个方法就可以了解创建bean和增强bean功能的整个过程。这里先贴出这三个方法的源码,省略了其中部分对理解生命周期不是特别重要的代码,比如异常处理之类的,然后对生命周期中重要的步骤进行了注释并标号,后面会对这些步骤详细讲解,可以对照来看。

AbstractAutowireCapableBeanFactory中第一个重要的方法——createBean

  1. // AbstractAutowireCapableBeanFactory中的createBean方法
  2. protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
  3. RootBeanDefinition mbdToUse = mbd;
  4. // 1、进行类加载
  5. Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
  6. ...
  7. // 2、如果用户实现了InstantiationAwareBeanPostProcessor,则直接返回bean,并结束剩余创建流程(很少用到)
  8. Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
  9. if (bean != null) {
  10. return bean;
  11. }
  12. // 调用doCreateBean方法,这是上面提到的第二个重要的方法
  13. Object beanInstance = doCreateBean(beanName, mbdToUse, args);
  14. return beanInstance;
  15. }

AbstractAutowireCapableBeanFactory中第二个重要的方法——doCreateBean

  1. // AbstractAutowireCapableBeanFactory中的doCreateBean方法
  2. protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
  3. BeanWrapper instanceWrapper = null;
  4. if (mbd.isSingleton()) {
  5. instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
  6. }
  7. if (instanceWrapper == null) {
  8. // 3、推断构造器并实例化bean
  9. instanceWrapper = createBeanInstance(beanName, mbd, args);
  10. }
  11. Object bean = instanceWrapper.getWrappedInstance();
  12. Class<?> beanType = instanceWrapper.getWrappedClass();
  13. if (beanType != NullBean.class) {
  14. mbd.resolvedTargetType = beanType;
  15. }
  16. // Allow post-processors to modify the merged bean definition.
  17. if (!mbd.postProcessed) {
  18. // 4、BeanDefinition的后置处理器,可以更改bean的属性等(很少用到)
  19. applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
  20. mbd.postProcessed = true;
  21. }
  22. ...
  23. Object exposedObject = bean;
  24. // 5、处理依赖关系(依赖注入)
  25. populateBean(beanName, mbd, instanceWrapper);
  26. // 调用initializeBean方法,这是上面提到的第三个重要的方法
  27. exposedObject = initializeBean(beanName, exposedObject, mbd);
  28. ...
  29. return exposedObject;
  30. }

AbstractAutowireCapableBeanFactory中第三个重要的方法——initializeBean:

  1. // AbstractAutowireCapableBeanFactory中的initializeBean方法
  2. protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
  3. if (System.getSecurityManager() != null) {
  4. AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
  5. invokeAwareMethods(beanName, bean);
  6. return null;
  7. }, getAccessControlContext());
  8. } else {
  9. // 6、执行aware接口(第一处扩展点)
  10. invokeAwareMethods(beanName, bean);
  11. }
  12. Object wrappedBean = bean;
  13. if (mbd == null || !mbd.isSynthetic()) {
  14. // 7、执行bean后置处理器的前方法(第二处扩展点)
  15. wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  16. }
  17. // 8、执行初始化方法(第三处扩展点)
  18. invokeInitMethods(beanName, wrappedBean, mbd);
  19. if (mbd == null || !mbd.isSynthetic()) {
  20. // 9、执行bean后置处理器的后方法(第四处扩展点)
  21. wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  22. }
  23. return wrappedBean;
  24. }

上面标号的注释就是创建bean和增强bean的九个步骤,其中第二和第四步很少用到,剩余的七个都很重要,下面具体来看。

2.1 实例化之前:加载类

在前面有提到,扫描类的时候并没有进行类加载,但是实例化一个对象就必须要先进行类加载,所以AbstractAutowireCapableBeanFactory类的createBean()方法中做的第一件事就是进行类加载,对应上面源码中标号为1的注释的位置:

  1. // 1、resolveBeanClass方法进行类加载
  2. Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

2.2 实例化之前:可以提前返回bean(很少用到)

Spring允许不按照正常流程来创建一个Bean,开发者可以实现InstantiationAwareBeanPostProcessor接口,并在这个接口的postProcessBeforeInstantiation方法中返回一个Bean对象,如果这个对象不为空,就会结束剩余的创建流程,提前返回这个bean,这个bean如果是单例的话依然会放入到单例池中,只是不会进行依赖注入和功能增强。

  1. // 2、提前返回bean,并结束生命周期
  2. Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
  3. if (bean != null) {
  4. return bean;
  5. }

不过这种用法很少会用到,基本可以忽略这种用法。

2.3 推断构造器并实例化

实例化对象当然需要用到构造器,Spring可以推断构造器,选择合适的构造器来进行bean的实例化。

  1. // 3、推断构造器并实例化bean
  2. instanceWrapper = createBeanInstance(beanName, mbd, args);

推断构造方法其实没那么复杂:
如果只有一个无参的构造方法,那么实例化就只能使用这个构造方法了。
如果有多个构造方法,其中一个是无参构造方法,其余的是有参构造方法,这些构造方法都没有@AutoWired注解,也没有在xml文件中进行设置,那么spring会默认选择无参构造方法。
如果有多个构造器,都是有参构造器,这些构造器上没有@AutoWired注解,也没有在xml文件中进行设置,spring启动时会报错。
如果只有一个有参构造器,这个构造器上没有@AutoWired注解,也没有在xml文件中进行设置,spring会看这个有参构造器的参数(可能是其它bean或者常量)是不是都能获取到,如果不能都获取到就会报错,如果都能获取到就会用这个构造器。

其它情况就看用户指定了哪个构造器,指定构造器有两种方式,一是通过@Autowired注解,二是通过xml中的<constructor-arg>标签来指定构造器参数,spring会根据参数来选择构造器,如果能找到一个合适的构造器,spring就会使用用户指定的构造器。但如果用户指定了多个构造器,比如在多个构造器上使用@Autowired注解或者通过xml标签不能推断出一个唯一的构造器,spring也会报错。

可能情况还不止上面这些,但是整体思路就是看spring能否找到一个不存在歧义的构造器(唯一的构造器或用户唯一指定的构造器),如果能找到,那么就使用这个构造器,如果找不到就看用户是否允许spring自动选择构造器,如果不允许就报错,如果允许就看spring自动选择的这个构造的参数是否都能获取到,如果都能获取到就会使用这个构造器,如果不能都获取到就会报错。

2.4 BeanDefinition的后置处理(很少用到)

在BeanDefinition的后置处理中可以修改BeanDefinition,但是此时实例对象已经生成好了,所以想通过修改beanClass来改变bean对象已经没用了,但是这个时候bean只是实例化出来,还没进行依赖注入,所以可以修改PropertyValues:

  1. if (!mbd.postProcessed) {
  2. try {
  3. // 4、BeanDefinition的后置处理器,可以更改bean的属性等
  4. applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
  5. }
  6. catch (Throwable ex) {
  7. ...
  8. }
  9. mbd.postProcessed = true;
  10. }

这种用法也很少会用到,基本可以忽略。

2.5 填充属性(依赖注入)

populateBean()方法进行了属性填充,所谓属性填充其实就是依赖注入,spring会先去容器中寻找依赖的bean,如果找到了就直接注入,如果没有找到就会去创建依赖的bean,所以这个方法是一个递归的入口,等依赖的bean创建完之后,会接着进行当前bean的属性注入。这里就涉及到spring bean循环依赖的问题,这是一个比较复杂的问题,用一个单独的篇章来讲,详见:源码解析Spring循环依赖

  1. // 5、处理依赖关系(依赖注入)
  2. populateBean(beanName, mbd, instanceWrapper);

上面创建bean的步骤细分有很多步,但如果粗略划分,其实最重要的只有两步:一是实例化,二是属性填充,这两步也是创建一个java对象的过程

三、增强bean功能

在属性填充结束之后,从java的角度来说这个bean已经是一个完整的java对象,可以使用了。但是spring框架更进一步,通过各种扩展点来对bean的功能进行增强,这些扩展点都是用户可选的,并不是必须的

3.1 扩展点:Aware接口

第一处扩展点就是Aware接口,Aware单词有"发现.../对...有兴趣"的含义,从名字就可以看出来aware接口让用户能够从spring容器中获取一些有用的、感兴趣的信息或对象。Aware接口的执行对应上面源码中标号为6的注释的位置:

  1. // 6、执行aware接口(第一处扩展点)
  2. invokeAwareMethods(beanName, bean);

Aware接口有很多,这里列举几个常见的:

beanFactory和aplicationContext是spring容器不同程度上的抽象,BeanFactory接口定义了容器应该具有的基础行为,只要一个类实现了BeanFactory接口,我们就可以称它为容器。ApplicationContext接口组合了BeanFactory接口和一些其它接口,所以ApplicationContext接口扩展了容器的行为,我们称实现了BeanFactory接口的类为容器,那么实现了ApplicationContext接口的类也是容器,只是这个容器会具有更多的行为,使用起来会更加方便。

一个正在运行的spring应用只会有一个容器,但是jvm中可以同时有beanFactory和aplicationContext对象,这是不矛盾的,这种情况下beanFactory对象是aplicationContext对象的一个属性,相当于aplicationContext对象静态代理了beanFactory对象,这属于实现上的细节。正因为jvm中可以同时有beanFactory和aplicationContext对象,所以我们可以在一个bean上同时实现BeanFactoryAware和ApplicationContextAware接口,虽然这么做没有意义。

  1. @Component
  2. public class BeanC implements BeanFactoryAware, ApplicationContextAware {
  3. private BeanFactory beanFactory;
  4. private ApplicationContext applicationContext;
  5. @Override
  6. public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
  7. this.beanFactory = beanFactory;
  8. }
  9. @Override
  10. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  11. this.applicationContext = applicationContext;
  12. }
  13. }

BeanFactoryAware和ApplicationContextAware接口可以让我们获取到spring容器,这其实是实现依赖查找的关键,所谓依赖查找就是事先不进行bean的注入,而是在需要使用的时候从容器中查找,既然要从容器中查找,那必然要先获取容器对象,这两个接口可以让我们获取容器对象。

3.2、扩展点:初始化方法之前

从通用的设计角度来说,一个框架可以允许用户在对象实例化完成之后执行一些操作,这些操作统一放在一个方法中,叫做初始化方法。Spring也一样,当spring将一个bean实例化完成之后,就会执行这个初始化方法。但是在这个初始化方法的前后还可以增加扩展点,做到全方位的可扩展,这就是bean后置处理器(BeanPostProcessor)的前方法和后方法,前方法就是初始化之前执行的方法,后方法是初始化之后执行的方法。
前方法的执行对应上面源码中标号为7的注释的位置:

  1. // 7、执行bean后置处理器的前方法(第二处扩展点)
  2. wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

由于Bean后置处理器是比较重要的一块功能,涉及的内容也很多,所以用一个单独的章节讲解,详细内容请跳转到第六章。

这里面有一个特别要关注的点是@PostConstruct注解,这个注解用于标注一个方法,这个方法会在在bean实例化结束之后执行一些操作,和初始化方法的作用是一样的,但是我们知道@PostConstruct注解标注的方法会在初始化方法之前执行,这可以在Spring实现这个注解的方式中找到原因。细心的小伙伴会发现这个注解是javax包中的注解,并不是Spring自己的注解,Spring使用了CommonAnnotationBeanPostProcessor这个bean后置处理器来处理javax包中常用的注解,@PostConstruct注解就是其中之一,而且是在前方法中去执行这个注解标注的方法,这就是为什么@PostConstruct注解标注的方法会在初始化方法之前执行的原因,在第六章有源码解析,可以跳转查看。

与之相对的是@PreDestroy注解,这个注解也是javax包中的注解,也通过CommonAnnotationBeanPostProcessor的前方法来处理,但是和@PostConstruct不一样,@PostConstruct标注的方法会在前方法中直接执行,而@PreDestroy不会直接执行,而是暂时保存起来等到bean销毁之前执行。

3.3 扩展点:初始化方法

Spring允许用户自定义一些操作,这些操作会在bean实例化完成之后执行,这些操作放在一个统一的方法中叫做初始化方法。
初始化方法有多种指定方式,这里列举最为常用的两种,第一种是实现InitializingBean接口,在这个接口的afterPropertiesSet()方法中定义初始化操作;第二种是在xml配置文件中通过init-method标签指定初始化方法,现在用xml配置文件的方式已经比较少了。这两种方式可以共存,会先执行在afterPropertiesSet()方法,然后执行init-method标签指定初始化方法,但是一般不会有人同时混用这两种方式。

初始化方法的执行对应上面源码中标号为8的注释的位置:

  1. // 8、执行初始化方法(第三处扩展点)
  2. invokeInitMethods(beanName, wrappedBean, mbd);

3.4 扩展点:初始化方法之后

初始化方法之后的扩展点就是bean后置处理器的后方法,这里典型的应用就是Spring AOP的功能实现,Spring AOP底层用的是动态代理,代理对象就是在Bean后置处理器的后方法中进行生成的,详细内容请跳转到第六章。
后方法的执行对应于上面源码中标号为9的注释的位置:

  1. // 9、执行bean后置处理器的后方法(第四处扩展点)
  2. wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

这一步执行完之后一个bean就真正意义的创建完成,如果是单例bean还会加入到单例池中,之后就可以真正使用了,直到最后在容器关闭的时候被销毁。

四、单例bean的销毁

容器销毁的时候会进行单例bean的销毁。可以想象一下,如果所有单例bean都没有定义销毁方法,那么容器只需要直接清空保存单例bean的缓存就可以了。但如果有一些单例bean定义了销毁方法,就需要找出这些单例bean,执行销毁方法,执行完之后再清空单例bean的缓存。所以先要找出那些定义了销毁方法的bean,然后执行这些销毁方法。有多种方式来定义销毁方法,这里列举最为常用的三种方式

Spring使用了适配器模式来统一这些销毁方法的处理方式,这个适配器就是DisposableBeanAdapter,最终会在这个适配器中的destroy方法中来执行具体的销毁方法。

  1. // DisposableBeanAdapter中的destroy方法
  2. @Override
  3. public void destroy() {
  4. if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
  5. // 执行@PreDestroy注解标注的方法
  6. for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
  7. processor.postProcessBeforeDestruction(this.bean, this.beanName);
  8. }
  9. }
  10. if (this.invokeDisposableBean) {
  11. try {
  12. if (System.getSecurityManager() != null) {
  13. AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
  14. ((DisposableBean) this.bean).destroy();
  15. return null;
  16. }, this.acc);
  17. }
  18. else {
  19. // 执行DisposableBean接口的destroy()方法
  20. ((DisposableBean) this.bean).destroy();
  21. }
  22. }
  23. catch (Throwable ex) {
  24. ...
  25. }
  26. }
  27. // 执行xml标签中指定的销毁方法或者其他方式指定的销毁方法
  28. if (this.destroyMethod != null) {
  29. invokeCustomDestroyMethod(this.destroyMethod);
  30. } else if (this.destroyMethodName != null) {
  31. Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
  32. if (methodToInvoke != null) {
  33. invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
  34. }
  35. }
  36. }

上面提到的三种销毁方法可以同时存在,先执行@PreDestroy标注的方法,然后执行DisposableBean接口的destroy()方法,最后执行xml中destry-method标签指定的销毁方法。当然没有必要同时混用这几中方法。

五、总结

Spring Bean是java对象的一种特例,所以和java对象一样需要实例化和填充属性,但是Spring作为框架还可以在bean实例化并填充属性之后进行各种功能增强。实例化、填充属性、增强功能这是Spring Bean生命周期最为主要的三个阶段,如果简略划分甚至可以把这三个阶段作为Spring Bean的生命周期。当然如果进一步细分就是如下五个阶段:

最后来看一看Spring Bean生命周期中有一些成对的接口或者注解,比如:

这些成对的接口或注解用于定义一些初始化操作和销毁操作,在使用上都是类似的,执行顺序上也是类似的,初始化时先执行@PostConstruct注解标注的方法,然后是afterPropertiesSet()方法,然后是init-method指定的方法;销毁时先执行@PreDestroy注解标注的方法,然后是destroy()方法,然后是destroy-method标签指定的方法。

六、扩展章节:Bean后置处理器

Spring允许一个bean实例化完成之后执行一些操作,这些操作统一放在一个方法中,叫做初始化方法,在这个初始化方法的前后还可以增加功能扩展点,这两个扩展点就是通过bean的后置处理器(BeanPostProcesser接口)来完成的,在初始化方法之前的扩展点对应的是BeanPostProcesser的postProcessBeforeInitialization()方法,为了便于描述可以简单称为bean后置处理器的前方法;初始化方法之后的扩展点对应的是BeanPostProcesser的postProcessAfterInitialization()方法,称为bean后置处理器的后方法。之所以叫做bean的后置处理器,是因为它是在bean实例化完成之后执行的。

  1. public interface BeanPostProcessor {
  2. //bean初始化方法调用前被调用
  3. @Nullable
  4. default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  5. return bean;
  6. }
  7. //bean初始化方法调用后被调用
  8. @Nullable
  9. default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  10. return bean;
  11. }
  12. }

可以看到BeanPostProcesser是一个接口,开发者可以自己实现BeanPostProcesser接口来对bean进行某种功能的增强。但是BeanPostProcesser接口和Aware接口不一样,Aware接口是bean直接继承的,影响的只有实现接口的这一个bean,而BeanPostProcesser接口是需要单独实现的,影响的是所有的用户bean,Spring启动的时候会先注册所有的bean后置处理器,然后创建bean,所以一旦一个BeanPostProcesser注册成功就会在所有bean的创建过程中执行。
比如按如下代码自定义一个Bean后置处理器:

  1. @Component
  2. public class MyBeanPostProcessor implements BeanPostProcessor {
  3. @Override
  4. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  5. System.out.println(beanName + ": Exec before init");
  6. return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
  7. }
  8. @Override
  9. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  10. System.out.println(beanName + ": Exec after init");
  11. return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
  12. }
  13. }

那么所有的bean在创建过程中都会打印日志。

6.1 Spring中的Bean后置处理器

BeanPostProcesser是一个接口,我们可以自己实现这个接口,用于在bean初始化方法之前和之后进行功能增强。另一方面,Spring本身也运用这个接口来实现一些功能。典型的例子就是CommonAnnotationBeanPostProcessor和AnnotationAwareAspectJAutoProxyCreator,这两个类都实现了BeanPostProcessor接口,所以都是Bean后置处理器,但是要注意这两个类还实现了其它接口,功能是复杂的,并不是单纯的Bean后置处理器。

6.1.1 典型例子之一:CommonAnnotationBeanPostProcessor

CommonAnnotationBeanPostProcessor这个类用来处理javax包中扩展的注解,这些注解包括@Resource、@WebServiceRef、@EJB、@PostConstruct、@PreDestroy,这五个注解中最为常用的是@Resource、@PostConstruct、@PreDestroy,但是这5个注解中只有@PostConstruct和@PreDestroy这两个注解用到了Bean后置处理器接口,看源码:

  1. // CommonAnnotationBeanPostProcessor继承了InitDestroyAnnotationBeanPostProcessor,InitDestroyAnnotationBeanPostProcessor中有前方法和后方法的具体实现:
  2. @Override
  3. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  4. // 在bean的class中寻找是否有@PostConstruct和@PreDestroy这两个注解,构造LifecycleMetadata对象
  5. LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
  6. try {
  7. // 如果有@PostConstruct注解,将直接执行这个注解标注的方法
  8. metadata.invokeInitMethods(bean, beanName);
  9. }
  10. catch (InvocationTargetException ex) {
  11. ...
  12. } catch (Throwable ex) {
  13. ...
  14. }
  15. return bean;
  16. }
  17. @Override
  18. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  19. return bean;
  20. }

可以看到CommonAnnotationBeanPostProcessor的前方法中扫描了bean的Class对象,看其中是否有@PostConstruct和@PreDestroy这两个注解,然后构造出LifecycleMetadata对象。如果有@PostConstruct注解,这个注解标注的方法还会在前方法中立刻执行,@PreDestroy则是在bean销毁之前执行。

其它的三个注解则没有通过Bean后置处理器的前后方法进行处理,之前说过CommonAnnotationBeanPostProcessor是复杂的,不仅实现了BeanPostProcessor接口,也实现了其它接口,这几个注解是通过其它接口定义的方法实现的,有兴趣可以去看源码,这里聚焦于Bean后置处理器的功能,所以不进行展开。

我们知道@Resource注解和@Autowired注解对应,都用于进行依赖注入,@Resource通过CommonAnnotationBeanPostProcessor来实现,@Autowired则是通过AutowiredAnnotationBeanPostProcessor来实现的,这个类用来处理@AutoWired、@Values、 java.inject.Inject这三个注解,AutowiredAnnotationBeanPostProcessor同样继承了BeanPostProcessor这个接口,所以也是bean后置处理器,但是看源码就会发现这个Bean后置处理器的前、后方法都是空方法,所以这些注解的功能都是通过其它接口定义的方法来实现的,之所以要把这个类定义为Bean的后置处理器只是为了统一处理:Spring在启动的时候会先扫描所有的Bean后置处理器并注册,这个过程中会把AutowiredAnnotationBeanPostProcessor给注册进去。

@Resource注解和@Autowired注解不使用bean后置处理器来实现的原因也很容易理解,这两个注解是用来进行依赖注入的,spring创建bean的时候是先处理依赖注入(populateBean方法),然后才会执行bean后置处理器的前后方法(initializeBean方法),如果这两个注解使用bean后置处理器来实现和创建bean的流程矛盾了。

6.1.2 典型例子之二:AnnotationAwareAspectJAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator用于实现Spring的AOP功能。我们知道Spring的AOP底层用的是动态代理技术,这意味着在Spring容器中最终保存的应该是增强过后的代理对象,而不是原始的对象,那Spring是怎么做到这一点的呢?其实就是用到了BeanPostProcesser接口,在BeanPostProcesser接口的后方法中判断当前bean是否需要植入切面逻辑,如果需要就生成一个代理对象。这个实现了BeanPostProcesser接口的类是AnnotationAwareAspectJAutoProxyCreator,看源码:

  1. // AnnotationAwareAspectJAutoProxyCreator继承自AbstractAutoProxyCreator,在这个类中有后方法的实现
  2. @Override
  3. public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
  4. if (bean != null) {
  5. Object cacheKey = getCacheKey(bean.getClass(), beanName);
  6. if (this.earlyProxyReferences.remove(cacheKey) != bean) { // 有关循环依赖
  7. // 如果检测到aop的设置,则创建代理对象
  8. return wrapIfNecessary(bean, beanName, cacheKey);
  9. }
  10. }
  11. return bean;
  12. }

这里还牵扯到循环依赖相关的事项,这里不进行展开,有单独的篇章讲解,见:源码解析Spring循环依赖

6.2 BeanPostProcess的顺序

从上面的讲解可以看到Spring框架本身已经有了很多bean后置处理器,开发者自己也可以定义很多bean后置处理器,那这些bean后置处理器的执行顺序是什么样的呢?我们来看注册Bean后置处理器的实现逻辑,其实原本的注释已经解释的很详细了:

  1. // 注册方法在PostProcessorRegistrationDelegate这个工具类中
  2. public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
  3. String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
  4. // Register BeanPostProcessorChecker that logs an info message when
  5. // a bean is created during BeanPostProcessor instantiation, i.e. when
  6. // a bean is not eligible for getting processed by all BeanPostProcessors.
  7. int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
  8. beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
  9. // 处理bean后置处理器的主要思路是将bean后置处理器进行分离,将实现了PriorityOrdered接口、Ordered接口的bean后置处理器和剩余的进行分离,分别排序之后再分别向spring容器注册
  10. // Separate between BeanPostProcessors that implement PriorityOrdered,
  11. // Ordered, and the rest.
  12. List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
  13. List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
  14. List<String> orderedPostProcessorNames = new ArrayList<>();
  15. List<String> nonOrderedPostProcessorNames = new ArrayList<>();
  16. for (String ppName : postProcessorNames) {
  17. if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
  18. BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
  19. priorityOrderedPostProcessors.add(pp);
  20. if (pp instanceof MergedBeanDefinitionPostProcessor) {
  21. internalPostProcessors.add(pp);
  22. }
  23. }
  24. else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
  25. orderedPostProcessorNames.add(ppName);
  26. }
  27. else {
  28. nonOrderedPostProcessorNames.add(ppName);
  29. }
  30. }
  31. // 首先注册实现了PriorityOrdered接口的bean后置处理器,这包括AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor
  32. // First, register the BeanPostProcessors that implement PriorityOrdered.
  33. sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
  34. registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
  35. // 然后注册实现了Ordered接口的bean后置处理器,这包括AnnotationAwareAspectJAutoProxyCreator
  36. // Next, register the BeanPostProcessors that implement Ordered.
  37. List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
  38. for (String ppName : orderedPostProcessorNames) {
  39. BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
  40. orderedPostProcessors.add(pp);
  41. if (pp instanceof MergedBeanDefinitionPostProcessor) {
  42. internalPostProcessors.add(pp);
  43. }
  44. }
  45. sortPostProcessors(orderedPostProcessors, beanFactory);
  46. registerBeanPostProcessors(beanFactory, orderedPostProcessors);
  47. // 然后注册剩余的bean后置处理器,包括用户自定义的普通bean后置处理器(没有实现PriorityOrdered接口和Ordered接口),这些后置处理器按加载的顺序放入到list中,加载是按照字典序加载的,所以这里的顺序也是字典序
  48. // Now, register all regular BeanPostProcessors.
  49. List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
  50. for (String ppName : nonOrderedPostProcessorNames) {
  51. BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
  52. nonOrderedPostProcessors.add(pp);
  53. if (pp instanceof MergedBeanDefinitionPostProcessor) {
  54. internalPostProcessors.add(pp);
  55. }
  56. }
  57. registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
  58. // 最后重新注册internalPostProcessors中的bean后置处理器,也就是那些实现了MergedBeanDefinitionPostProcessor接口的bean后置处理器,包括AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor,重新注册会将这些bean后置处理器从列表的前面移除,然后放到列表的最后。
  59. // Finally, re-register all internal BeanPostProcessors.
  60. sortPostProcessors(internalPostProcessors, beanFactory);
  61. registerBeanPostProcessors(beanFactory, internalPostProcessors);
  62. // Re-register post-processor for detecting inner beans as ApplicationListeners,
  63. // moving it to the end of the processor chain (for picking up proxies etc).
  64. beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
  65. }

上面代码关键步骤我添加了中文注释,处理bean后置处理器的主要思路是将bean后置处理器进行分离,将实现了PriorityOrdered接口、Ordered接口的Bean后置处理器和剩余的进行分离,分别排序之后再分别向spring容器注册,所谓注册就是将这些Bean后置处理器放入到容器中的一个List中去,这里要注意都是是先排序再注册,放入到容器中的list之后不会再进行排序,也就是说先注册的必然在list的前面。

AnnotationAwareAspectJAutoProxyCreator的order是Ordered.LOWEST_PRECEDENCE(值为2147483647),是最低的优先级;CommonAnnotationBeanPostProcessor也是这个值,也是最低的优先级;AutowiredAnnotationBeanPostProcessor是Ordered.LOWEST_PRECEDENCE - 2,比CommonAnnotationBeanPostProcessor略高一点;用户自定义的bean后置处理器一般不会实现PriorityOrdered接口和Ordered接口,则是按照加载的顺序排序,也就是字典序。按照源码执行的流程,容器中bean后置处理器最终的顺序是:

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注