准备
refresh 方法
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 刷新前预处理
prepareRefresh();
// 获取之前创建的BeanFactory,默认实现DefaultListableBeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,设置类加载器,环境等等。
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// 实例化并调用默认配置,和自定义的BeanFactoryPostProcessor,实现核心配置类解析,包组件扫描封装BeanDefinition.
invokeBeanFactoryPostProcessors(beanFactory);
// 注册默认配置的和自定义的BeanPostProcessor , 实现bean创建赋值之后 init 方法前后调用
registerBeanPostProcessors(beanFactory);
// 初始化MessageSource组件,实现 国际化功能,消息绑定,消息解析
initMessageSource();
// 初始化应用事件派发器
initApplicationEventMulticaster();
// 子类重写
onRefresh();
// 注册实现了ApplicationListener接⼝的监听器
registerListeners();
// 实例化剩下的所有单例bean
finishBeanFactoryInitialization(beanFactory);
// 发布事件,交由其它组件触发对应响应,例如springMVC初始化
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
注意这个invokeBeanFactoryPostProcessors(beanFactory); 方法。
注意此时IOC容器中的BeanDefinitionMap中已经存在一些系统默认的,和核心配置类BeanDefinition
点击去发现,这里先调用 实现了PriorityOrdered的BeanDefinitionRegistryPostProcessors
然后调用实现了Ordered的BeanDefinitionRegistryPostProcessors
最后调用其它剩余的BeanDefinitionRegistryPostProcessors。
从实现了PriorityOrdered的BeanDefinitionRegistryPostProcessors开始剖析,从BeanDefinitionMap中获取实现该接口的BeanDefinition(ConfigurationClassPostProcessor),然后实例化,接着调用postProcessor方法
ConfigurationClassPostProcessor 主要实现对 @Configuration的核心配置类进行解析
ConfigurationClassPostProcessor 处理流程
1、从当前的BeanDefinitionMap中找到满足@Configuration的BeanDefinition
2、解析满足的每一个@Configuration类,而当前满足条件的@Configuration类是我们自己定义的核心配置类
3、解析我们配置的核心配置类,如果存在父类依次进行解析
4、正式解析@Configuration所在类
4.1、解析@PropertySource注解,实现外部配置文件加载
4.2、解析@ComponentScan注解,实现指定包下的组件扫描
4.2.1、获取@ComponentScan所有的属性,以basePackage为例
4.2.2、解析basePackage后面的包,对指定包进行扫描
4.2.3 获取编译后的target目录+ 我们直接指定的包路径 = 最终.class文件存在的位置。
将目标包,极其子包对应的组件,全部封装成BeanDefinition
找到目标包路径
封装BeanDefinition
最终可以获取到指定包下的所有组件BeanDefinition
4.3、解析@Import注解,实现其它配置文件载入
4.5、解析@Bean注解,通过 getAnnotatedMethods(Bean.class.getName()) 获取@Bean对应的所有方法
到此为止,spring对于启动时,定义的核心配置解析完成,对应的组件扫描也完成。这些组件都会被注册到IOC容器中BeanDefinitionMap当中
总结
spring如何对@Configuration定义的核心配置类进行解析?
1、在容器BeanFactory创建完成后,调用invokeBeanFactoryPostProcessor
2、invokeBeanFactoryPostProcessor中有一个实现了PriorityOrdered的BeanDefinitionRegistryPostProcessors(简称ConfigurationClassPostProcessor),实现对我们定义的核心配置类进行解析
3、解析@PropertySource,@Import,@ComponentScan,@Bean。
以@ComponentScan解析为例,获取当前项目编译后的target路径 + 自定义包路径 = 最终.class文件,将存在@Component等注解的组件,全部封装成BeanDefinition,放入IOC容器的BeanDefinitionMap当中,等待实例化。
解析流程为什么从核心配置类开始
1、我们使用AnnotationConfigApplicationContext来创建和启动容器,那么默认加载核心配置文件,成BeanDefinition,放入容器
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(ApplicationContextConfiguration.class);
2、而在invokeBeanFactoryPostProcessor中通过ConfigurationClassPostProcessor,实现对@Configuration进行解析,那么@Cofiguration对应的类,默认是从BeanDefinitionMap中获取,此时只有我们定义的核心配置类,因此从核心配置类开始组件扫描解析。
在SpringBoot中也是从启动类开始解析的,例如启动类上的@SpringBootApplication