【Spring源码】- 02 Spring IoC容器启动之refresh方法

183 阅读18分钟
原文链接: mp.weixin.qq.com

register

AnnotationConfigApplicationContext构造方法中三个方法中第一个方法上面分析过了,现在我们来看下第二个方法: register(componentClasses)

之前使用XML方式: new ClassPathXmlApplicationContext("classpath:spring.xml");,构造方法中需要指定xml配置文件路径,然后就可以解析 xml文件中<bean><context:component-scan>等配置进行IoC启动初始化。同理,使用注解方式也需要给 Context指定一个起始配置源头,使用配置类代替xml配置文件,然后根据这个起始配置类一步步的解析下去。


                            @Configuration@ComponentScan(basePackageClasses = {TestConfig.class})@Import(TestService03.class)
                                public class TestConfig { @Bean 
                                    public TestService01 testService01(){  
                                        return new TestService01(); }}
                                            

通过这个配置类,Spring就可以解析 @ComponentScan@Import@Bean等这些注解,实现Bean注入到 IoC容器中。@Configuration注解定义的配置类就相当于之前 xml配置文件,不过由于现在Spring主流都推荐注解方式, xml方案使用的概率会越来越低。

跟踪register(componentClasses)方法,核心逻辑在: AnnotatedBeanDefinitionReader#doRegisterBean

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,   @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,   @Nullable BeanDefinitionCustomizer[] customizers) {  //先把此实体类型转换为一个BeanDefinition  AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);  /**   * abd.getMetadata()元数据包括注解信息、是否内部类、类Class基本信息等等   * 此处由conditionEvaluator#shouldSkip去过滤,此Class是否是配置类   * 大体逻辑为:必须有@Configuration修饰,然后解析一些Condition注解,看是否排除~   */  if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {   return;  }  abd.setInstanceSupplier(supplier);  // 解析Scope  ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);  abd.setScope(scopeMetadata.getScopeName());  // 得到Bean的名称 一般为首字母小写(此处为AnnotationBeanNameGenerator)  String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));  // 设定一些注解默认值,如lazy、Primary等等  AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);  if (qualifiers != null) {// 解析qualifiers,若有此注解  则primary都成为true了   for (Class<? extends Annotation> qualifier : qualifiers) {    if (Primary.class == qualifier) {     abd.setPrimary(true);    }    else if (Lazy.class == qualifier) {     abd.setLazyInit(true);    }    else {     abd.addQualifier(new AutowireCandidateQualifier(qualifier));    }   }  }  if (customizers != null) {// 自定义定制信息(一般都不需要)   for (BeanDefinitionCustomizer customizer : customizers) {    customizer.customize(abd);   }  }  // 下面解析Scope是否需要代理,最后把这个Bean注册进去  BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);  definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);  BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);}

就是将传入的配置类解析成解析成BeanDefinition,注册到 IoC容器中,后续ConfigurationClassPostProcessor这个 BeanFactory后置处理器在IoC开始真正初始化时,可以获取到这些配置类的 BeanDefinition集合,启动解析。

refresh

前面分析了AnnotationConfigApplicationContext构造方法中前两个,这两个方法基本都是 IoC启动的前戏:为IoC容器的启动做热身准备;真正的 IoC容器启动初始化流程是在refresh()方法中,这是了解 IoC容器启动流程最关键、核心的一个方法。

refresh方法定义在 AbstractApplicationContext,采用模板模式,定义好IoC启动的流程以及每个步骤的作用,并提供基础实现,其它子类可以重写进行扩展。


                                                public void refresh
                                                    () throws BeansException, IllegalStateException { synchronized (
                                                        this.startupShutdownMonitor) {  //Context进行刷新前的准备工作  prepareRefresh();  
                                                            // 创建并初始化 BeanFactory,这步会将BeanDefinition载入到BeanFactory中  ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
                                                                /**  * 填充BeanFactory功能  * 上面获取获取的 BeanFactory其实还不能投入生产,因为还少配置了一些东西,比如 context的 ClassLoader 和 后置处理器等等。  */  prepareBeanFactory(beanFactory);  
                                                                    try {   /**   * 默认空实现,留给子类扩展使用   * 可以参照:AbstractRefreshableWebApplicationContext#postProcessBeanFactory()   */   postProcessBeanFactory(beanFactory);   
                                                                        /**   * 调用BeanFactory后置处理器(包括BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor)   */   invokeBeanFactoryPostProcessors(beanFactory);   registerBeanPostProcessors(beanFactory);   
                                                                            //初始化消息源   initMessageSource();   //初始化应用上下文事件广播器   initApplicationEventMulticaster();   
                                                                                //初始化其它特殊的Bean,由具体子类实现   onRefresh();   //注册事件监听器   registerListeners();   
                                                                                    //初始化所有单实例Bean,使用懒加载模式的Bean除外   finishBeanFactoryInitialization(beanFactory);   //完成刷新并发布容器刷新事件   finishRefresh();  }  
                                                                                        catch (BeansException ex) {   ...//省略  }  
                                                                                            finally {   resetCommonCaches();  } }}
                                                                                                

下面就来分析下每个方法作用,以了解IoC容器的启动流程。

prepareRefresh

prepareRefresh从方法名称可以看出,该方法主要在 refresh执行前进行一些简单的准备工作,如设置Context的启动时间、状态,以及系统属性相关扩展。


                                                                                                         /**  * 初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验,如环境变量中必须设置某个值才能运行,否则不能运行,这个时候可以在这里加这个校验,重写initPropertySources方法就好了  *  * 该方法主要是做一些准备工作,如:  *  1、设置 context 启动时间  *  2、设置 context 的当前状态  *  3、初始化 context environment 中占位符  *  4、对属性进行必要的验证  */ 
                                                                                                            protected void prepareRefresh
                                                                                                                () {  //设置启动时间  
                                                                                                                    this.startupDate = System.currentTimeMillis();  //设置context当前状态  
                                                                                                                        this.closed.set(false);//标志context状态:未关闭  
                                                                                                                            this.active.set(true);//标志context状态:活跃中  
                                                                                                                                /**   * 初始化context environment(上下文环境)中属性源信息,默认这里是空实现,什么都没做,这里主要提供给子类扩展,采用模板设计模式   * 比如非web环境下,context
                                                                                                                                    environment是StandardEnvironment类型,只会在创建时初始化两类属性源:systemEnvironment(系统环境变量)   * 和systemProperties(应用环境变量),通过
                                                                                                                                    @PropertySource注解等方式配置这时是还没有加载的   *   *   * 该方法主要有两个常见扩展:   * 
                                                                                                                                        1、可以在该类中扩展PropertySource来源,如:getEnvironment().getPropertySources().addXXX(PropertySource ps),可以参见GenericWebApplicationContext#initPropertySources()   *  2、可以在方法中添加必要属性验证,一些属性对于应用来说是必要的,缺失则会影响系统的正常逻辑,   *   如:getEnvironment().setRequiredProperties("DB_IP"),下一步就会从context
                                                                                                                                        environment上验证是否存在该属性,如果没有则会抛出异常并退出Spring应用   */  initPropertySources();  
                                                                                                                                        /**   * 对属性必要性进行校验,逻辑参见:AbstractPropertyResolver#validateRequiredProperties   */  getEnvironment().validateRequiredProperties();  
                                                                                                                                            //早期事件监听器集合如果为空,就新建一个;如果不为空,就先清空事件监听器集合,然后将早期事件监听器整体放入事件监听器集合。  if (
                                                                                                                                                this.earlyApplicationListeners == null) {   
                                                                                                                                                    //默认情况下,earlyApplicationListeners为null   this.earlyApplicationListeners = 
                                                                                                                                                        new LinkedHashSet<>(this.applicationListeners);  }  
                                                                                                                                                            else {   this.applicationListeners.clear();   
                                                                                                                                                                this.applicationListeners.addAll(this.earlyApplicationListeners);  }  
                                                                                                                                                                    //保存容器中的一些早期事件,待事件派发器multicaster初始化完成后进行事件发布  this.earlyApplicationEvents = 
                                                                                                                                                                        new LinkedHashSet<>();}
                                                                                                                                                                            

这里主要注意下initPropertySources()getEnvironment().validateRequiredProperties()这两句代码。PropertySourceSpring中代表一组变量,即类似对应于一个配置文件,比如@PropertySource("test01.properties")这个常用的注解就是将配置文件解析成一个 PropertySource对象。

initPropertySources()方法主要用于扩展配置来源,比如可以从网络、物理文件、数据库等加载配置信息。 StandardEnvironment在创建时,会自动将系统变量System.getProperties()和应用变量 System.getenv()加载进来,所以initPropertySources默认只提供的是空实现,主要用于子类扩展使用。

initPropertySources方法主要有两个常见扩展场景:

  • 1、可以在该类中扩展PropertySource来源,如: getEnvironment().getPropertySources().addXXX(PropertySource ps),可以参见 GenericWebApplicationContext#initPropertySources()
  • 2、可以在方法中添加必要属性验证,一些属性对于应用来说是必要的,缺失则会影响系统的正常逻辑,如:getEnvironment().setRequiredProperties("DB_IP"),下一步就会从 context environment上验证是否存在该属性,如果没有则会抛出异常并退出Spring应用

getEnvironment().validateRequiredProperties()这句主要是对 setRequiredProperties()方法设置的属性进行必要性检查,如果某个必要属性环境中不存在,则抛出异常退出应用。

obtainFreshBeanFactory

BeanFactory才是 Spring中基本的IoC容器, ApplicationContext其实内部包装了一个BeanFactory,并对其进行了增强,使其更智能、更好用。 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();这句主要意思是:通知 Context,我要开始使用IoC容器进行初始化工作了,请提供给我一个 BeanFactory容器。这个方法比较简单,基本没有需要扩展的,就不再仔细研究。

prepareBeanFactory

上面获取获取的BeanFactory容器其实还不能投入生产,因为还缺少一些配置信息,这里主要向 BeanFactory填充一些必要的配置。


                                                                                                                                                                                                                            protected 
                                                                                                                                                                                                                                void prepareBeanFactory
                                                                                                                                                                                                                                    (ConfigurableListableBeanFactory beanFactory) { 
                                                                                                                                                                                                                                        // 设置beanFactory的classLoader beanFactory.setBeanClassLoader(getClassLoader()); 
                                                                                                                                                                                                                                            // 设置beanFactory的表达式语言处理器,Spring3开始增加了对语言表达式的支持,默认可以使用#{bean.xxx}的形式来调用相关属性值 beanFactory.setBeanExpressionResolver(
                                                                                                                                                                                                                                                new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); 
                                                                                                                                                                                                                                                    // 为beanFactory增加一个默认的propertyEditor beanFactory.addPropertyEditorRegistrar(
                                                                                                                                                                                                                                                        new ResourceEditorRegistrar(
                                                                                                                                                                                                                                                            this, getEnvironment())); 
                                                                                                                                                                                                                                                                // 添加一个ApplicationContextAwareProcessor类型的Bean后置处理器,该后置处理器用于处理*Aware接口的依赖注入 beanFactory.addBeanPostProcessor(
                                                                                                                                                                                                                                                                    new ApplicationContextAwareProcessor(
                                                                                                                                                                                                                                                                        this)); 
                                                                                                                                                                                                                                                                            /** * 自动装配时如下接口中setter方法的依赖注入会被忽略 * 如:EnvironmentAware#setEnvironment()该setter不能用于自动装配时依赖注入方法, * 因为这些*Aware接口统一采用ApplicationContextAwareProcessor这个Bean后置处理器进行依赖注入 */ beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); 
                                                                                                                                                                                                                                                                                /** * 设置几个自动装配的特殊规则 *
                                                                                                                                                                                                                                                                                    DefaultListableBeanFactory#findAutowireCandidates(DependencyDescriptor
                                                                                                                                                                                                                                                                                    ds)在查找依赖注入值时: * 
                                                                                                                                                                                                                                                                                    1、首先会从resolvableDependencies容器中查找,如果有直接返回找到的bean进行依赖注入; *  2、如果没有,再从IoC容器中查找 * 所以,resolvableDependencies容器可以看成对常规IoC的一种扩充 */ beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, 
                                                                                                                                                                                                                                                                                    this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, 
                                                                                                                                                                                                                                                                                        this); beanFactory.registerResolvableDependency(ApplicationContext.class, 
                                                                                                                                                                                                                                                                                            this); 
                                                                                                                                                                                                                                                                                                /** * 添加一个ApplicationListenerDetector类型的Bean后置处理器,将类型是ApplicationListener的bean添加到事件广播器,以便触发事件时被调用 */ beanFactory.addBeanPostProcessor(
                                                                                                                                                                                                                                                                                                    new ApplicationListenerDetector(
                                                                                                                                                                                                                                                                                                        this)); 
                                                                                                                                                                                                                                                                                                            /** * 增加对AspectJ的支持 * 检查容器中是否包含名称为loadTimeWeaver的bean,实际上是增加Aspectj的支持 *     AspectJ采用编译期织入、类加载期织入两种方式进行切面的织入 *     类加载期织入简称为LTW(Load
                                                                                                                                                                                                                                                                                                                Time
                                                                                                                                                                                                                                                                                                                Weaving),通过特殊的类加载器来代理JVM默认的类加载器实现 */ 
                                                                                                                                                                                                                                                                                                                if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {  
                                                                                                                                                                                                                                                                                                                    // 添加BEAN后置处理器:LoadTimeWeaverAwareProcessor  
                                                                                                                                                                                                                                                                                                                        // 在BEAN初始化之前检查BEAN是否实现了LoadTimeWeaverAware接口,  
                                                                                                                                                                                                                                                                                                                            // 如果是,则进行加载时织入,即静态代理。  beanFactory.addBeanPostProcessor(
                                                                                                                                                                                                                                                                                                                                new LoadTimeWeaverAwareProcessor(beanFactory));  beanFactory.setTempClassLoader(
                                                                                                                                                                                                                                                                                                                                    new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } 
                                                                                                                                                                                                                                                                                                                                        // 注册默认的系统环境bean    
                                                                                                                                                                                                                                                                                                                                            // 这样应用程序中通过:getBean("environment")、getBean("systemProperties")、getBean("systemEnvironment") 
                                                                                                                                                                                                                                                                                                                                                if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {  beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } 
                                                                                                                                                                                                                                                                                                                                                    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {  beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } 
                                                                                                                                                                                                                                                                                                                                                        if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {  beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); }}
                                                                                                                                                                                                                                                                                                                                                            

上面逻辑大致可以总结:

  • BeanFactory设置 ClassLoaderEL表达式解析器等;

  • 添加一个BeanPostProcessorApplicationContextAwareProcessor,这个主要完成对*Aware接口功能支持,实现的核心逻辑见下:判断是否实现了 XXXAware接口,如果实现则调用对应的setter方法注入依赖值。

private void invokeAwareInterfaces(Object bean) { if (bean instanceof EnvironmentAware) {  ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) {  ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) {  ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) {  ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) {  ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) {  ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); }}
  • ignoreDependencyInterface方法设置一些忽略接口:自动装配时如遇到忽略接口中 setter方法的依赖注入会被忽略,因为这些*Aware接口统一采用 ApplicationContextAwareProcessor这个后置处理器进行依赖注入。

  • registerResolvableDependency方法设置一些特殊的内置对象, DefaultListableBeanFactory#findAutowireCandidates(DependencyDescriptor ds)在查找依赖注入值时:a、首先会从resolvableDependencies容器中查找,如果有直接返回找到的 bean进行依赖注入;b、如果没有,再从IoC容器中查找。因此, resolvableDependencies容器可以看出是对IoC容器的一种扩充,该容器中的对象是没有经过 Spring一系列容器创建流程,而是直接new方式创建。

  • 再添加一个Bean后置处理器: ApplicationListenerDetector,将系统中实现ApplicationListener接口的对象都统一存储到 Set<ApplicationListener<?>> applicationListeners中,采用了典型的事件监听/发布模式;

  • LTW功能判断, LTW全称LoadTimeWeaver,即:加载时织入。 AOPOOP一样,是一种编程思想,按照织入时机可以分为三类:编译时织入、类加载时织入和运行时织入。 AspectJ实现就是编译时织入,采用的是一种特殊的编译器;Spring AOP采用的动态代理实现( jdk动态代理、cglib动态代理),这是一种运行时织入,缺点就是必须纳入 IoC管理的Bean才能被代理;而 LTW是类加载时织入,借助于JVM提供的 Instrumentation技术,在JDK加载类时织入增强逻辑。

Instrumentation是在 JVM加载Class时进行代码织入,对现有应用没有任何的侵入, APM Agent开发中就比较常用该技术。

  • 注册三个环境变量相关Bean到容器中,这样应用中可以依赖注入到程序中进行使用;

    beanFactory.registerSingleton方式把对象存储到 singletonObjects集合中,它类似于一个缓存,从IoC获取 Bean时,首先会通过getSingleton方法从缓存拿,如果缓存拿不到再去获取对应的 BeanDefinition进行实例化,然后实例化对象放到singletonObjects集合中。

postProcessBeanFactory

postProcessBeanFactory(beanFactory)默认是空实现,主要是留给子类进行扩展,从名称上看该方法主要用于添加 BeanFactoryPostProcessorAnnotationConfigApplicationContext已经在前面注册了一个 ConfigurationClassPostProcessor,主要用于完成对Spring配置类的处理,其它子类可以重新这个方法增加其它 BeanFactoryPostProcessor对象,实现功能扩充。

invokeBeanFactoryPostProcessors

前面巴拉巴拉一大堆,基本还是各种配置、填充工作,这一步就到了IoC容器开始真正干活的阶段了。invokeBeanFactoryPostProcessors(beanFactory)方法主要就是完成对所有注册进来的 BeanFactory后置处理器执行调用,包括BeanFactoryPostProcessor及其子类 BeanDefinitionRegistryPostProcessor。这里就会有个前面提到的Spring中非常重要的一个类:ConfigurationClassPostProcessor开始被执行,它执行完成后,所有需要 Spring管理的Bean都会被解析成 BeanDefinition注册进来。由于ConfigurationClassPostProcessor非常的复杂,后续会单独分析这个类,这篇主要是对 IoC启动的流程有个大致的、直观印象。执行完这步,你只需要简单知道@Configuration@Bean@Import@ComponentScan@Component等等相关配置注解会被处理,相关的 Bean也被解析成BeanDefinition注册进来即可。


                        protected void invokeBeanFactoryPostProcessors
                            (ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // LTW探测 
                                if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {  beanFactory.addBeanPostProcessor(
                                    new LoadTimeWeaverAwareProcessor(beanFactory));  beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }}
                                        

getBeanFactoryPostProcessors()获取到 ApplicationContext.beanFactoryPostProcessors集合中存储的BeanFactoryPostProcessor,通过 addBeanFactoryPostProcessor()方法添加的,这里集合为空,因为从前面代码看并没有调用过该方法。

这里核心在invokeBeanFactoryPostProcessors()方法。首先,看下 if (beanFactory instanceof BeanDefinitionRegistry)判断,如果容器不是BeanDefinitionRegistry类型或子类,则表示当前容器不能向容器注册 Bean,所以只需要执行BeanFactoryPostProcessor类型后置处理器即可, BeanDefinitionRegistryPostProcessor后置处理器不需要执行,因为该后置处理器主要是用来向IoC容器中注册 Bean,大部分我们使用的容器都是BeanDefinitionRegistry类型,这样才能把我们业务 Bean纳入Spring管理,所以基本上都是走 if语句块

//判断我们的beanFactory是否实现了BeanDefinitionRegistryif (beanFactory instanceof BeanDefinitionRegistry) { ...//省略}else { invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}

invokeBeanFactoryPostProcessors方法核心就是执行 BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor,但是涉及到执行优先级、执行后可能会产生新 PostProcessor等,所以这里的代码看起来比较长,总结下执行逻辑大致如下:

1、先执行BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry方法,其中BeanDefinitionRegistryPostProcessor执行优先级如下:	a、addBeanFactoryPostProcessor()传入到优先级最高,因为不需要实例化,直接可以获取到对象进行执行;	b、然后从IoC容器中获取PriorityOrdered接口的BeanDefinitionRegistryPostProcessor,实例化并排序后执行postProcessBeanDefinitionRegistry方法	c、然后从IoC容器中获取Ordered接口的BeanDefinitionRegistryPostProcessor,实例化并排序后执行postProcessBeanDefinitionRegistry方法	d、然后从IoC容器中获取剩余的BeanDefinitionRegistryPostProcessor,实例化后执行postProcessBeanDefinitionRegistry方法;注意这个处理步骤存在一个循环,主要是存在执行前面的BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry方法时,存在可能会向IoC容器中注册新的BeanDefinitionRegistryPostProcessor,通过循环保证都会被执行;2、然后执行BeanDefinitionRegistryPostProcessor#postProcessBeanFactory方法,执行顺序参照步骤1中执行顺序;3、最后才会执行BeanFactoryPostProcessor#postProcessBeanFactory,执行优先级和BeanDefinitionRegistryPostProcessor一致:	a、addBeanFactoryPostProcessor()传入到优先级最高,因为不需要实例化,直接可以获取到对象进行执行;	b、然后从IoC容器中获取PriorityOrdered接口的BeanFactoryPostProcessor,实例化并排序后执行postProcessBeanFactory方法	c、然后从IoC容器中获取Ordered接口的BeanFactoryPostProcessor,实例化并排序后执行postProcessBeanFactory方法	d、然后从IoC容器中获取剩余的BeanFactoryPostProcessor,实例化后执行postProcessBeanFactory方法

这里有个细节,在执行BeanFactoryPostProcessor#postProcessBeanFactory方法是没有循环,而执行 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry中存在一个循环,主要是因为BeanFactoryPostProcessor#postProcessBeanFactory方法是不会像 IoC中注册Bean,这样执行过程中就不会产生新的 BeanFactoryPostProcessor

上面写了一大堆,概况下就是:

1、方法优先级:BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry > BeanDefinitionRegistryPostProcessor#postProcessBeanFactory > BeanFactoryPostProcessor#postProcessBeanFactory

2、同方法优先级:addBeanFactoryPostProcessor > PriorityOrdered > Ordered > 非排序

registerBeanPostProcessors

registerBeanPostProcessors方法主要是将 BeanDefinition对应的BeanPostProcessor实例化并通过 beanFactory.addBeanPostProcessor()方法注册进来。前面分析过AnnotationConfigUtils.registerAnnotationConfigProcessors会向容器注册几个 Spring内置的BeanPostProcessor,这步主要是将应用中引入的 BeanPostProcessor注册进来。

上步invokeBeanFactoryPostProcessors执行完成后, Spring会将所有的Bean解析成 BeanDefinition注册到容器中,其中就可能包含BeanPostProcessorBeanDefinition信息,这个方法就是把这些BeanPostProcessor对应的 BeanDefinition通过getBean方式实例化,并通过 addBeanPostProcessor()注册进来,这样这些BeanPostProcessor才能起作用。

这个方法代码巴拉巴拉一大堆,流出总结起来还是很清晰,这里就不再上代码:

  1. 获取实现PriorityOrdered接口的 BeanPostProcessor,然后通过getBean()方法实例化,排序后注册到容器中;
  2. 获取实现Ordered接口的 BeanPostProcessor,然后通过getBean()方法实例化,排序后注册到容器中;
  3. 获取常规没有实现PriorityOrderedOrdered接口BeanPostProcessor,然后通过 getBean()方法实例化,注册到容器中;
  4. 上述步骤中MergedBeanDefinitionPostProcessor类型会单独存储到 internalPostProcessors集合中,排序后保证放到末尾;
  5. 最后移除ApplicationListenerDetector重新追加到最末尾。

注意:这里有个细节就是要保证高级别优先级的BeanPostProcessor全部实例化完成后,才可以进行下一个优先级类型的 BeanPostProcessor,因为BeanPostProcessor主要就是围绕 Bean实例化进行扩展,这样就可以保证高优先级的BeanPostProcessor可以参与到对低优先级的 BeanPostProcessor实例化过程中。

和上步invokeBeanFactoryPostProcessors不同的是,这里只是把所有的 BeanPostProcessor注册进来,并没有去执行,因为这也很好理解:BeanPostProcessor是围绕在 Bean实例化周围的扩展点,这里服务Bean存储在容器中基本都还是 BeanDefinition,还没有进行实例化。

initMessageSource

initMessageSource方法主要是处理国际化相关工作,后台开发中很少涉及,这里就不展开分析。

initApplicationEventMulticaster

initApplicationEventMulticaster是上下文环境中初始化一个事件广播器,用于事件发布,后续分析 Spring事件机制再整体分析。

onRefresh

onRefresh默认是空实现,模板模式设计主要用于子类扩展。可以参照 SpringBootServletWebServerApplicationContext这个类,重写了 onRefresh()方法,在这个方法中完成内嵌Servlet容器的创建: TomcatJettyUndertow,将程序内嵌一个Servlet容器后,就可以独立运行。

registerListeners

registerListeners方法主要完成事件监听器注册,将实现了 ApplicationListener接口的监听器bean注册到 ApplicationEventMulticaster上,在注册完以后,还会将其前期的事件发布给相匹配的监听器。后续分析Spring事件机制再整体分析。