转载自:https://fangjian0423.github.io/2017/05/10/springboot-context-refresh/
上一篇文章中,我们分析了SpringBoot的启动过程:构造SpringApplication并调用它的run方法。其中构造SpringApplication的时候会初始化一些监听器和初始化器;run方法调用的过程中会有对应的监听器监听,并且会创建Spring容器。
Spring容器创建之后,会调用它的refresh方法,refresh的时候会做很多事情:比如完成配置类的解析、各种BeanFactoryPostProcessor和BeanPostProcessor的注册、国际化配置的初始化、web内置容器的构造等等。
我们来分析一下这个refresh过程。
还是以web程序为例,那么对应的Spring容器为AnnotationConfigEmbeddedWebApplicationContext。它的refresh方法调用了父类AbstractApplicationContext的refresh方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public void refresh() throws BeansException, IllegalStateException { // refresh过程只能一个线程处理,不允许并发执行 synchronized (this.startupShutdownMonitor) { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } } |
表示在真正做refresh操作之前需要准备做的事情:
从Spring容器获取BeanFactory(Spring Bean容器)并进行相关的设置为后续的使用做准备:
BeanFactory设置之后再进行后续的一些BeanFactory操作。
不同的Spring容器做不同的操作。比如GenericWebApplicationContext容器会在BeanFactory中添加ServletContextAwareProcessor用于处理ServletContextAware类型的bean初始化的时候调用setServletContext或者setServletConfig方法(跟ApplicationContextAwareProcessor原理一样)。
AnnotationConfigEmbeddedWebApplicationContext对应的postProcessBeanFactory方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 调用父类EmbeddedWebApplicationContext的实现 super.postProcessBeanFactory(beanFactory); // 查看basePackages属性,如果设置了会使用ClassPathBeanDefinitionScanner去扫描basePackages包下的bean并注册 if (this.basePackages != null && this.basePackages.length > 0) { this.scanner.scan(this.basePackages); } // 查看annotatedClasses属性,如果设置了会使用AnnotatedBeanDefinitionReader去注册这些bean if (this.annotatedClasses != null && this.annotatedClasses.length > 0) { this.reader.register(this.annotatedClasses); } } |
父类EmbeddedWebApplicationContext的实现:
1 2 3 4 5 6 |
@Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { beanFactory.addBeanPostProcessor( new WebApplicationContextServletContextAwareProcessor(this)); beanFactory.ignoreDependencyInterface(ServletContextAware.class); } |
在Spring容器中找出实现了BeanFactoryPostProcessor接口的processor并执行。Spring容器会委托给PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法执行。
介绍两个接口:
基于web程序的Spring容器AnnotationConfigEmbeddedWebApplicationContext构造的时候,会初始化内部属性AnnotatedBeanDefinitionReader reader,这个reader构造的时候会在BeanFactory中注册一些post processor,包括BeanPostProcessor和BeanFactoryPostProcessor(比如ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor):
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
invokeBeanFactoryPostProcessors方法处理BeanFactoryPostProcessor的逻辑如下:
从Spring容器中找出BeanDefinitionRegistryPostProcessor类型的bean(这些processor是在容器刚创建的时候通过构造AnnotatedBeanDefinitionReader的时候注册到容器中的),然后按照优先级分别执行,优先级的逻辑如下:
接下来从Spring容器内查找BeanFactoryPostProcessor接口的实现类,然后执行(如果processor已经执行过,则忽略),这里的查找规则跟上面查找BeanDefinitionRegistryPostProcessor一样,先找PriorityOrdered,然后是Ordered,最后是两者都没。
这里需要说明的是ConfigurationClassPostProcessor这个processor是优先级最高的被执行的processor(实现了PriorityOrdered接口)。这个ConfigurationClassPostProcessor会去BeanFactory中找出所有有@Configuration注解的bean,然后使用ConfigurationClassParser去解析这个类。ConfigurationClassParser内部有个Map
这里ConfigurationClassPostProcessor最先被处理还有另外一个原因是如果程序中有自定义的BeanFactoryPostProcessor,那么这个PostProcessor首先得通过ConfigurationClassPostProcessor被解析出来,然后才能被Spring容器找到并执行。(ConfigurationClassPostProcessor不先执行的话,这个Processor是不会被解析的,不会被解析的话也就不会执行了)。
在我们的程序中,只有主类RefreshContextApplication有@Configuration注解(@SpringBootApplication注解带有@Configuration注解),所以这个配置类会被ConfigurationClassParser解析。解析过程如下:
这里@SpringBootApplication注解被@EnableAutoConfiguration修饰,@EnableAutoConfiguration注解被@Import(EnableAutoConfigurationImportSelector.class)修饰,所以在第3步会找出这个@Import修饰的类EnableAutoConfigurationImportSelector,这个类刚好实现了DeferredImportSelector接口,接着就会在第6步被执行。第6步selectImport得到的类就是自动化配置类。
EnableAutoConfigurationImportSelector的selectImport方法会在spring.factories文件中找出key为EnableAutoConfiguration对应的值,有81个,这81个就是所谓的自动化配置类(XXXAutoConfiguration)。
ConfigurationClassParser解析完成之后,被解析出来的类会放到configurationClasses属性中。然后使用ConfigurationClassBeanDefinitionReader去解析这些类。
这个时候这些bean只是被加载到了Spring容器中。下面这段代码是ConfigurationClassBeanDefinitionReader的解析bean过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
public void loadBeanDefinitions(Set |
invokeBeanFactoryPostProcessors方法总结来说就是从Spring容器中找出BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor接口的实现类并按照一定的规则顺序进行执行。 其中ConfigurationClassPostProcessor这个BeanDefinitionRegistryPostProcessor优先级最高,它会对项目中的@Configuration注解修饰的类(@Component、@ComponentScan、@Import、@ImportResource修饰的类也会被处理)进行解析,解析完成之后把这些bean注册到BeanFactory中。需要注意的是这个时候注册进来的bean还没有实例化。
下面这图就是对ConfigurationClassPostProcessor后置器的总结:
从Spring容器中找出的BeanPostProcessor接口的bean,并设置到BeanFactory的属性中。之后bean被实例化的时候会调用这个BeanPostProcessor。
该方法委托给了PostProcessorRegistrationDelegate类的registerBeanPostProcessors方法执行。这里的过程跟invokeBeanFactoryPostProcessors类似:
这些已经存在的BeanPostProcessor在postProcessBeanFactory方法中已经说明,都是由AnnotationConfigUtils的registerAnnotationConfigProcessors方法注册的。这些BeanPostProcessor包括有AutowiredAnnotationBeanPostProcessor(处理被@Autowired注解修饰的bean并注入)、RequiredAnnotationBeanPostProcessor(处理被@Required注解修饰的方法)、CommonAnnotationBeanPostProcessor(处理@PreDestroy、@PostConstruct、@Resource等多个注解的作用)等。
如果是自定义的BeanPostProcessor,已经被ConfigurationClassPostProcessor注册到容器内。
这些BeanPostProcessor会在这个方法内被实例化(通过调用BeanFactory的getBean方法,如果没有找到实例化的类,就会去实例化)。
在Spring容器中初始化一些国际化相关的属性。
在Spring容器中初始化事件广播器,事件广播器用于事件的发布。
在SpringBoot源码分析之SpringBoot的启动过程中分析过,EventPublishingRunListener这个SpringApplicationRunListener会监听事件,其中发生contextPrepared事件的时候EventPublishingRunListener会把事件广播器注入到BeanFactory中。
所以initApplicationEventMulticaster不再需要再次注册,只需要拿出BeanFactory中的事件广播器然后设置到Spring容器的属性中即可。如果没有使用SpringBoot的话,Spring容器得需要自己初始化事件广播器。
一个模板方法,不同的Spring容器做不同的事情。
比如web程序的容器AnnotationConfigEmbeddedWebApplicationContext中会调用createEmbeddedServletContainer方法去创建内置的Servlet容器。
目前SpringBoot只支持3种内置的Servlet容器:
把Spring容器内的时间监听器和BeanFactory中的时间监听器都添加的事件广播器中。
然后如果存在early event的话,广播出去。
实例化BeanFactory中已经被注册但是未实例化的所有实例(懒加载的不需要实例化)。
比如invokeBeanFactoryPostProcessors方法中根据各种注解解析出来的类,在这个时候都会被初始化。
实例化的过程各种BeanPostProcessor开始起作用。
refresh做完之后需要做的其他事情。
Spring容器的refresh过程就是上述11个方法的介绍。内容还是非常多的,本文也只是说了个大概,像bean的实例化过程没有具体去分析,这方面的内容以后会看情况去做分析。
这篇文章也是为之后的文章比如内置Servlet容器的创建启动、条件注解的使用等打下基础。
写了一个例子用来验证容器的refresh过程,包括bean解析,processor的使用、Lifecycle的使用等。
可以启动项目debug去看看对应的过程,这样对Spring容器会有一个更好的理解。
地址在:https://github.com/fangjian0423/springboot-analysis/tree/master/springboot-refresh-context