Spring容器创建后,会调用它的refresh方法,refresh的时候会做很多事情:如完成配置类解析、各种BeanFactoryPostProcessor和BeanPostProcessor的注册、国际化配置的初始化、web内置容器的构造等等。
web程序对应Spring容器为AnnotationConfigServletWebServerApplicationContext。
ServletWebServerApplicationContext接受带注解的类作为输入,特别是 @Configuration 类,也接受使用普通 @Component 类和符合 JSR-330 的 javax.inject 类。允许逐个注册类(将类名指定为配置位置)以及类路径扫描(将基本包指定为配置位置)。 如有多个 @Configuration 类,以后 @Bean 的定义将覆盖在早期加载的文件中定义的定义。可以利用这一点,通过额外的配置类有意覆盖某些 Bean 定义。
其refresh方法调用父类
0 AbstractApplicationContext
1@Override2public void refresh() throws BeansException, IllegalStateException {3 // refresh过程只能一个线程处理,不允许并发执行4 synchronized (this.startupShutdownMonitor) {5 StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");67 // Prepare this context for refreshing.8 prepareRefresh();910 // Tell the subclass to refresh the internal bean factory.11 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();1213 // Prepare the bean factory for use in this context.14 prepareBeanFactory(beanFactory);1516 try {17 // Allows post-processing of the bean factory in context subclasses.18 postProcessBeanFactory(beanFactory);1920 StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");21 // Invoke factory processors registered as beans in the context.22 invokeBeanFactoryPostProcessors(beanFactory);2324 // Register bean processors that intercept bean creation.25 registerBeanPostProcessors(beanFactory);26 beanPostProcess.end();2728 // Initialize message source for this context.29 initMessageSource();3031 // Initialize event multicaster for this context.32 initApplicationEventMulticaster();3334 // Initialize other special beans in specific context subclasses.35 onRefresh();3637 // Check for listener beans and register them.38 registerListeners();3940 // Instantiate all remaining (non-lazy-init) singletons.41 finishBeanFactoryInitialization(beanFactory);4243 // Last step: publish corresponding event.44 finishRefresh();45 }4647 catch (BeansException ex) {48 if (logger.isWarnEnabled()) {49 logger.warn("Exception encountered during context initialization - " +50 "cancelling refresh attempt: " + ex);51 }5253 // Destroy already created singletons to avoid dangling resources.54 destroyBeans();5556 // Reset 'active' flag.57 cancelRefresh(ex);5859 // Propagate exception to caller.60 throw ex;61 }6263 finally {64 // Reset common introspection caches in Spring's core, since we65 // might not ever need metadata for singleton beans anymore...66 resetCommonCaches();67 contextRefresh.end();68 }69 }70}
1 prepareRefresh
真正refresh操作前需要准备做的事:
- 设置Spring容器的启动时间,撤销关闭状态,开启活跃状态
- 初始化属性源信息(Property)
- 验证环境信息里一些必须存在的属性
2 prepareBeanFactory
从Spring容器获取BeanFactory(Spring Bean容器)并进行相关的设置为后续的使用做准备:
1 protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {2 // Tell the internal bean factory to use the context's class loader etc.3 4 // 设置classloader(用于加载bean)5 beanFactory.setBeanClassLoader(getClassLoader());6 // 设置表达式解析器(解析bean定义中的一些表达式)7 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));8 // 添加属性编辑注册器(注册属性编辑器)9 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));1011 // Configure the bean factory with context callbacks.12 // 添加ApplicationContextAwareProcessor这个BeanPostProcessor13 // 取消ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware、EnvironmentAware这5个接口的自动注入14 // 因为ApplicationContextAwareProcessor把这5个接口实现工作做了15 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));16 beanFactory.ignoreDependencyInterface(EnvironmentAware.class);17 beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);18 beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);19 beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);20 beanFactory.ignoreDependencyInterface(MessageSourceAware.class);21 beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);22 beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);2324 // BeanFactory interface not registered as resolvable type in a plain factory.25 // MessageSource registered (and found for autowiring) as a bean.26 27 // 设置特殊的类型对应的bean。BeanFactory对应刚刚获取的BeanFactory;ResourceLoader、ApplicationEventPublisher、ApplicationContext这3个接口对应的bean都设置为当前的Spring容器28 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);29 beanFactory.registerResolvableDependency(ResourceLoader.class, this);30 beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);31 beanFactory.registerResolvableDependency(ApplicationContext.class, this);3233 // Register early post-processor for detecting inner beans as ApplicationListeners.34 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));3536 // Detect a LoadTimeWeaver and prepare for weaving, if found.37 if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {38 beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));39 // Set a temporary ClassLoader for type matching.40 beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));41 }4243 // Register default environment beans.44 // 注入一些其它信息的bean45 if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {46 beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());47 }48 if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {49 beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());50 }51 if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {52 beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());53 }54 if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {55 beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());56 }57 }
3 postProcessBeanFactory
BeanFactory设置之后再进行后续的一些BeanFactory操作。
不同的Spring容器做不同的操作。比如GenericWebApplicationContext容器会在BeanFactory中添加ServletContextAwareProcessor用于处理ServletContextAware类型的bean初始化的时候调用setServletContext或者setServletConfig方法(ApplicationContextAwareProcessor原理)。
AnnotationConfigEmbeddedWebApplicationContext对应的postProcessBeanFactory方法:
1AnnotationConfigServletWebServerApplicationContext.java23@Override4protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {5 // 调用父类EmbeddedWebApplicationContext实现6 super.postProcessBeanFactory(beanFactory);7 // 查看basePackages属性,如设置了,使用ClassPathBeanDefinitionScanner扫描basePackages包下的bean并注册8 if (this.basePackages != null && this.basePackages.length > 0) {9 this.scanner.scan(this.basePackages);10 }11 // 查看annotatedClasses属性,如设置了,使用AnnotatedBeanDefinitionReader注册这些bean12 if (this.annotatedClasses != null && this.annotatedClasses.length > 0) {13 this.reader.register(this.annotatedClasses);14 }15}
父类EmbeddedWebApplicationContext实现
ServletContextAwareProcessor的变体,用于 ConfigurableWebApplicationContext.可以在注册处理器时使用,可以在 或 ServletConfig 已经初始化之前ServletContext发生。
1public class WebApplicationContextServletContextAwareProcessor extends ServletContextAwareProcessor {23 private final ConfigurableWebApplicationContext webApplicationContext;45 public WebApplicationContextServletContextAwareProcessor(ConfigurableWebApplicationContext webApplicationContext) {6 Assert.notNull(webApplicationContext, "WebApplicationContext must not be null");7 this.webApplicationContext = webApplicationContext;8 }9 ...10}
4 invokeBeanFactoryPostProcessors方法
在Spring容器中找出实现了BeanFactoryPostProcessor#processor并执行。Spring容器会委托给PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors。
- BeanFactoryPostProcessor:修改Spring容器中已存在的bean的定义,使用ConfigurableListableBeanFactory对bean进行处理
- BeanDefinitionRegistryPostProcessor:继承BeanFactoryPostProcessor,作用跟BeanFactoryPostProcessor一样,只不过是使用BeanDefinitionRegistry对bean进行处理
基于web程序的Spring容器AnnotationConfigServletWebServerApplicationContext构造时,会初始化内部属性AnnotatedBeanDefinitionReader reader:
1public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext2 implements AnnotationConfigRegistry {34 private final AnnotatedBeanDefinitionReader reader;56 private final ClassPathBeanDefinitionScanner scanner;78 private final Set<Class<?>> annotatedClasses = new LinkedHashSet<>();910 private String[] basePackages;1112 public AnnotationConfigServletWebServerApplicationContext() {13 this.reader = new AnnotatedBeanDefinitionReader(this);14 this.scanner = new ClassPathBeanDefinitionScanner(this);15 }
这reader构造的时候会在BeanFactory中注册一些post processor,包括BeanPostProcessor和BeanFactoryPostProcessor(如ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor):
1AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
invokeBeanFactoryPostProcessors处理BeanFactoryPostProcessor
从Spring容器中找出BeanDefinitionRegistryPostProcessor类型的bean。
这些processor是在容器刚创建的时候通过构造AnnotatedBeanDefinitionReader的时候注册到容器中的,然后按优先级执行。
优先级逻辑:
- 实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor先全部找出来,然后排序后依次执行
- 实现Ordered接口的BeanDefinitionRegistryPostProcessor找出来,然后排序后依次执行
- 没有实现PriorityOrdered和Ordered接口的BeanDefinitionRegistryPostProcessor找出来执行并依次执行
接着,从Spring容器内查找BeanFactoryPostProcessor接口的实现类,然后执行(若processor已经执行过,则忽略),这里的查找规则跟上面查找BeanDefinitionRegistryPostProcessor一样,先找PriorityOrdered,然后是Ordered,最后是两者都没。
ConfigurationClassPostProcessor这个processor是优先级最高的被执行的processor(实现了PriorityOrdered接口)。这个ConfigurationClassPostProcessor会去BeanFactory中找出所有有@Configuration注解的bean,然后使用ConfigurationClassParser去解析这个类。ConfigurationClassParser内部有个Map<ConfigurationClass, ConfigurationClass>类型的configurationClasses属性用于保存解析的类,ConfigurationClass是一个对要解析的配置类的封装,内部存储了配置类的注解信息、被@Bean注解修饰的方法、@ImportResource注解修饰的信息、ImportBeanDefinitionRegistrar等都存储在这个封装类中。
这里ConfigurationClassPostProcessor最先被处理还有另外一个原因是如果程序中有自定义的BeanFactoryPostProcessor,那么这个PostProcessor首先得通过ConfigurationClassPostProcessor被解析出来,然后才能被Spring容器找到并执行。(ConfigurationClassPostProcessor不先执行的话,这个Processor是不会被解析的,不会被解析的话也就不会执行了)。
在我们的程序中,只有主类RefreshContextApplication有@Configuration注解(@SpringBootApplication注解带有@Configuration注解),所以这个配置类会被ConfigurationClassParser解析。解析过程如下:
- 处理@PropertySources注解:进行一些配置信息的解析
- 处理@ComponentScan注解:使用ComponentScanAnnotationParser扫描basePackage下的需要解析的类(@SpringBootApplication注解也包括了@ComponentScan注解,只不过basePackages是空的,空的话会去获取当前@Configuration修饰的类所在的包),并注册到BeanFactory中(这个时候bean并没有进行实例化,而是进行了注册。具体的实例化在finishBeanFactoryInitialization方法中执行)。对于扫描出来的类,递归解析
- 处理@Import注解:先递归找出所有的注解,然后再过滤出只有@Import注解的类,得到@Import注解的值。比如查找@SpringBootApplication注解的@Import注解数据的话,首先发现@SpringBootApplication不是一个@Import注解,然后递归调用修饰了@SpringBootApplication的注解,发现有个@EnableAutoConfiguration注解,再次递归发现被@Import(EnableAutoConfigurationImportSelector.class)修饰,还有@AutoConfigurationPackage注解修饰,再次递归@AutoConfigurationPackage注解,发现被@Import(AutoConfigurationPackages.Registrar.class)注解修饰,所以@SpringBootApplication注解对应的@Import注解有2个,分别是@Import(AutoConfigurationPackages.Registrar.class)和@Import(EnableAutoConfigurationImportSelector.class)。找出所有的@Import注解之后,开始处理逻辑:
- 遍历这些@Import注解内部的属性类集合
- 如果这个类是个ImportSelector接口的实现类,实例化这个ImportSelector,如果这个类也是DeferredImportSelector接口的实现类,那么加入ConfigurationClassParser的deferredImportSelectors属性中让第6步处理。否则调用ImportSelector的selectImports方法得到需要Import的类,然后对这些类递归做@Import注解的处理
- 如果这个类是ImportBeanDefinitionRegistrar接口的实现类,设置到配置类的importBeanDefinitionRegistrars属性中
- 其它情况下把这个类入队到ConfigurationClassParser的importStack(队列)属性中,然后把这个类当成是@Configuration注解修饰的类递归重头开始解析这个类
- 处理@ImportResource注解:获取@ImportResource注解的locations属性,得到资源文件的地址信息。然后遍历这些资源文件并把它们添加到配置类的importedResources属性中
- 处理@Bean注解:获取被@Bean注解修饰的方法,然后添加到配置类的beanMethods属性中
- 处理DeferredImportSelector:处理第3步@Import注解产生的DeferredImportSelector,进行selectImports方法的调用找出需要import的类,然后再调用第3步相同的处理逻辑处理
这里@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过程:
1public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {2 TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();3 for (ConfigurationClass configClass : configurationModel) {4 // 对每一个配置类,调用loadBeanDefinitionsForConfigurationClass方法5 loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);6 }7}89private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,10 TrackedConditionEvaluator trackedConditionEvaluator) {11 // 条件注解判断是否需跳过这个配置类12 if (trackedConditionEvaluator.shouldSkip(configClass)) {13 // 跳过配置类的话在Spring容器中移除bean的注册14 String beanName = configClass.getBeanName();15 if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {16 this.registry.removeBeanDefinition(beanName);17 }18 this.importRegistry.removeImportingClassFor(configClass.getMetadata().getClassName());19 return;20 }2122 if (configClass.isImported()) {23 // 如果自身是被@Import注释所import的,注册自己24 registerBeanDefinitionForImportedConfigurationClass(configClass);25 }26 // 注册方法中被@Bean注解修饰的bean27 for (BeanMethod beanMethod : configClass.getBeanMethods()) {28 loadBeanDefinitionsForBeanMethod(beanMethod);29 }30 // 注册@ImportResource注解注释的资源文件中的bean31 loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());32 // 注册@Import注解中的ImportBeanDefinitionRegistrar接口的registerBeanDefinitions33 loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());34}
invokeBeanFactoryPostProcessors方法总结来说就是从Spring容器中找出BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor接口的实现类并按照一定的规则顺序进行执行。 其中ConfigurationClassPostProcessor这个BeanDefinitionRegistryPostProcessor优先级最高,它会对项目中的@Configuration注解修饰的类(@Component、@ComponentScan、@Import、@ImportResource修饰的类也会被处理)进行解析,解析完成之后把这些bean注册到BeanFactory中。需要注意的是这个时候注册进来的bean还没有实例化。
ConfigurationClassPostProcessor后置器
5 registerBeanPostProcessors
从Spring容器中找出的BeanPostProcessor接口的bean,并设置到BeanFactory的属性。
之后bean被实例化时,会调用这个BeanPostProcessor。
该方法委托给PostProcessorRegistrationDelegate#registerBeanPostProcessors(类似invokeBeanFactoryPostProcessors):
- 先找出实现PriorityOrdered接口的BeanPostProcessor,添加到BeanFactory的BeanPostProcessor集合priorityOrderedPostProcessors
- 找出实现了Ordered接口的BeanPostProcessor添加到orderedPostProcessorNames集
- 两个接口都没实现的BeanPostProcessor加到nonOrderedPostProcessorNames集
这些BeanPostProcessor都由AnnotationConfigUtils#registerAnnotationConfigProcessors注册的。这些BeanPostProcessor包括有:
- AutowiredAnnotationBeanPostProcessor(处理被@Autowired注解修饰的bean并注入)
- RequiredAnnotationBeanPostProcessor(处理被@Required注解修饰的方法)
- CommonAnnotationBeanPostProcessor(处理@PreDestroy、@PostConstruct、@Resource等多个注解的作用)等。
如果是自定义的BeanPostProcessor,已经被ConfigurationClassPostProcessor注册到容器内。
这些BeanPostProcessor会在这个方法内被实例化(通过调用BeanFactory的getBean方法,如果没有找到实例化的类,就会去实例化)。
6 initMessageSource
在Spring容器中初始化一些国际化相关的属性。
7 initApplicationEventMulticaster
在Spring容器中初始化事件广播器,事件广播器用于事件的发布。
EventPublishingRunListener这个SpringApplicationRunListener会监听事件,其中发生contextPrepared事件的时候EventPublishingRunListener会把事件广播器注入到BeanFactory。
所以initApplicationEventMulticaster无需再次注册,只需拿出BeanFactory中的事件广播器,然后设置到Spring容器的属性。如未使用SpringBoot,Spring容器得需要自己初始化事件广播器。
8 onRefresh
可以重写以添加特定于上下文的刷新工作的模板方法,在实例化单例之前调用特殊 bean 的初始化。 默认实现为空。
1protected void onRefresh() throws BeansException {2 // For subclasses: do nothing by default.3}
模板方法,不同的Spring容器做不同事。如web程序的容器ServletWebServerApplicationContext调createWebServer创建内置的Servlet容器。
SpringBoot内置Servlet容器:
9 registerListeners
把Spring容器内的事件监听器和BeanFactory中的事件监听器都添加的事件广播器中。
如存在early event,广播出去。
10 finishBeanFactoryInitialization
实例化BeanFactory中已被注册但未实例化的所有实例(懒加载的无需实例化)。
比如invokeBeanFactoryPostProcessors方法中根据各种注解解析出来的类,在这个时候都会被初始化。
实例化的过程各种BeanPostProcessor开始起作用。
11finishRefresh
refresh做完之后需要做的其他事:
- 初始化生命周期处理器,并设置到Spring容器中(LifecycleProcessor)
- 调用生命周期处理器的onRefresh方法,这个方法会找出Spring容器中实现了SmartLifecycle接口的类并进行start方法的调用
- 发布ContextRefreshedEvent事件告知对应的ApplicationListener进行响应的操作
- 调用LiveBeansView的registerApplicationContext方法:如果设置了JMX相关的属性,则就调用该方法
- 发布EmbeddedServletContainerInitializedEvent事件告知对应ApplicationListener进行相应操作