如何对一个注解的default方法赋值(ResourcePostConstruct)

CommonAnnotationBeanPostProcessor解析@Resource、@PostConstruct、@PreDestroy注解

我们在之前的文章分析里已经知道AnnotationConfigServletWebServerApplicationContext在初始化时会实例化一些后置处理器,其中就包括CommonAnnotationBeanPostProcessor处理器,通过之前我们分析@Autowired注解解析流程知道比较关键的两个流程是通过MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()对需要处理的注解进行解析并封装成InjectionMetadata,然后通过InstantiationAwareBeanPostProcessor.postProcessProperties()方法对InjectionMetadata进行处理,把相应的对象或value找到并填充到属性中。而CommonAnnotationBeanPostProcessor

跟AutowiredAnnotationBeanPostProcessor继承体系是一样的,流程也差不多,只是在处理细节上稍微有一些区别。

CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition方法

如何对一个注解的default方法赋值(ResourcePostConstruct)(1)

首先调了父类的postProcessMergedBeanDefinition方法,而他的父类是InitDestroyAnnotationBeanPostProcessor,所以先看父类的实现逻辑:

InitDestroyAnnotationBeanPostProcessor.InitDestroyAnnotationBeanPostProcessor方法

如何对一个注解的default方法赋值(ResourcePostConstruct)(2)

代码结构几乎是一样的,那么我们重点关注的是InitDestroyAnnotationBeanPostProcessor处理的是哪些注解以及在什么时候开始注解逻辑。

如何对一个注解的default方法赋值(ResourcePostConstruct)(3)

调用细节这里就不多说了,跟@Autowired流程一样,从buildLifecycleMetadata方法可以看出:主要是解析initAnnotationType和destroyAnnotationType两个注解,然后封装成LifecycleElement和LifecycleMetadata,需要注意的是被修饰的方法必须是无参方法,那么initAnnotationType和destroyAnnotationType具体代表是哪两个注解呢

initAnnotationType和destroyAnnotationType具体代表是哪两个注解呢

如何对一个注解的default方法赋值(ResourcePostConstruct)(4)

从CommonAnnotationBeanPostProcessor的构造方法可以看出,initAnnotationType就是@PostConstruct注解,destroyAnnotationType就是@PreDestroy注解。initAnnotationType和destroyAnnotationType这两个注解的含义以及被这两个注解的解析过程已经了解了,那么什么时候对封装后的LifecycleElement和LifecycleMetadata进行处理呢?

LifecycleElement和LifecycleMetadata处理入口以及流程

这个流程就要回到bean的实例化流程里:通过doCreateBean方法对bean实例化时会先用无参构造器或工厂方法进行实例化类,然后用populateBean方法对实例化对象进行属性的填充,填充完之后用initializeBean方法对bean实例化时需要调用的一些初始化方法进行最后的调用,然后就算实例化完成了,在就注册了一些bean销毁时调用的后置处理器(DestructionAwareBeanPostProcessor)。而我们的@PostConstruct就是在initializeBean方法中处理,@PreDestroy在bean销毁时DestructionAwareBeanPostProcessor.postProcessBeforeDestruction方法中处理。

initializeBean方法处理@PostConstruct

如何对一个注解的default方法赋值(ResourcePostConstruct)(5)

  1. 对BeanNameAware、BeanClassLoaderAware、BeanFactoryAware中的方法进行调用
  2. 调用BeanPostProcessor.postProcessBeforeInitialization()方法
  3. 调用InitializingBean.afterPropertiesSet()方法和bean的自定义init方法
  4. 调用BeanPostProcessor.postProcessAfterInitialization()方法

而我们的@PostConstruct就是在BeanPostProcessor.postProcessBeforeInitialization()方法中被处理。

InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization()方法

如何对一个注解的default方法赋值(ResourcePostConstruct)(6)

如何对一个注解的default方法赋值(ResourcePostConstruct)(7)

如何对一个注解的default方法赋值(ResourcePostConstruct)(8)

可以看到实际上就是使用了反射调用了@PostConstruct修饰的方法。

InitDestroyAnnotationBeanPostProcessor.postProcessBeforeDestruction()方法

如何对一个注解的default方法赋值(ResourcePostConstruct)(9)

如何对一个注解的default方法赋值(ResourcePostConstruct)(10)

如何对一个注解的default方法赋值(ResourcePostConstruct)(11)

可以看到实际上就是使用了反射调用了@PreDestroy修饰的方法。

至此,InitDestroyAnnotationBeanPostProcessor对于@PostConstruct和@PreDestroy的处理逻辑就处理完了。我们接着看CommonAnnotationBeanPostProcessor中的postProcessMergedBeanDefinition()逻辑。

CommonAnnotationBeanPostProcessor.findResourceMetadata方法

如何对一个注解的default方法赋值(ResourcePostConstruct)(12)

如何对一个注解的default方法赋值(ResourcePostConstruct)(13)

resourceAnnotationTypes这个属性是使用下面这个static代码块初始化的

如何对一个注解的default方法赋值(ResourcePostConstruct)(14)

而@Resource注解会被封装成ResourceElement对象。

ResourceElement.getResourceToInject方法

如何对一个注解的default方法赋值(ResourcePostConstruct)(15)

可以看到@Resource默认是name进行注入,如果@Resource设置了name则以设置的为准否则以属性的变量名为准。

总结:
  1. CommonAnnotationBeanPostProcessor实际上处理了@PostConstruct、@PreDestroy和@Resource注解,但@PostConstruct、@PreDestroy是交给父类DestructionAwareBeanPostProcessor来处理。
  2. @PostConstruct是在bean已经实例化且属性也已经填充完后在initializeBean方法中进行处理,@PostConstruct在bean被销毁时处理
  3. @Resource注入时是按name来注入,name优先取@Resource中的name否则取变量名。而@Autowired默认是按classType注入,当找到多个classType类时按变量名注入。
,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页