一、背景
springboot1.5.9集成JavaMelody的时候, https://github.com/javamelody/javamelody/blob/without-spring-boot-starter/javamelody-for-spring-boot/src/main/java/hello/JavaMelodyConfiguration.java#L110 发现这种集成方式的配置采用的硬编码方式,不能根据配置文件进行配置。因此我就想将配置方式修改为从配置文件读取,我的第一想法是采用@Value注解,先把一个log参数读取进来,但是发现该参数一直不能生效。
第一步,将monitoringFilter以下的bean都注释掉,该配置就生效了。
第二步,逐步增加注释掉的bean,当去掉SpringDataSourceBeanPostProcessor 和 SpringRestTemplateBeanPostProcessor这两个bean的加载,log参数就加载进来了。
那是什么原因呢?
二、原因探析
2.1 表象的深入分析
1.经过查看源码发现,SpringDataSourceBeanPostProcessor和SpringRestTemplateBeanPostProcessor实现了BeanPostProcessor, PriorityOrdered这两个接口。
2.然后我就把这种实现方式抽离出来简化了数据结构和实现方便调试,代码在这里。
经过调试发现 实现了BeanPostProcessor, PriorityOrdered这两个接口的bean影响@Value的bean的加载。
注意: @Value的实现类AutowiredAnnotationBeanPostProcessor也实现了BeanPostProcessor, PriorityOrdered这两个接口。
而且,还多打出来一行信息:
020-08-08 20:50:32.412 INFO 2700 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'myConfiguration1' of type [com.example.issue.MyConfiguration1$$EnhancerBySpringCGLIB$$ed2d2a7f] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
据此推断,可能是MyConfiguration1启动时机过早,导致实现@Value注解的AutowiredAnnotationBeanPostProcessor没来得及实例化及注册呢。
2.2 BeanPostProcessor启动阶段对其依赖的Bean造成的影响
BeanPostProcessor的启动阶段包括四个阶段
- 第一阶段applicationContext内置阶段
- 第二阶段priorityOrdered阶段
- 第三阶段Ordered阶段
- 第四阶段nonOrdered阶段
第一阶段的代码在AbstractApplicationContext.refresh()的 prepareBeanFactory()方法里,这里就不展示代码了。
第二阶段到第四阶段实例化和注册过程如下:
// 启动 Spring 应用上下文
AbstractApplicationContext.refresh()
//注册BeanPostProcessors
-> AbstractApplicationContext.registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory)
//调用委托执行post processors任务的工具类PostProcessorRegistrationDelegate去执行注册逻辑
-> PostProcessorRegistrationDelegate.registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext)
然后分成三个阶段依次实例化并注册实现了PriorityOrdered的BeanPostProcessor、实现了Ordered的BeanPostProcessor、普通的BeanPostProcessor(没实现Ordered),代码如下:
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>()</