spring 容器初始化流程

spring 专栏收录该内容
2 篇文章 0 订阅

 

上图是我看spring容器初始化源码的思维导图,转载YurBatman大神的总结, 写的很好,要多读好几遍。

1、prepareRefresh()刷新前的预处理;
    0)、this.closed.set(false),this.active.set(true)  设置一些标记位
    1)、initPropertySources()初始化一些属性设置;(交由子类去实现,比如web容器中的 AbstractRefreshableWebApplicationContext 就去初始化了servlet的一些init参数等等)
    2)、getEnvironment().validateRequiredProperties();检验属性的合法等
    3)、earlyApplicationEvents= new LinkedHashSet<ApplicationEvent>();初始化容器,保存一些早期的事件;
    
2、obtainFreshBeanFactory();获取BeanFactory;
    1)、refreshBeanFactory();抽象方法,子类【AbstractRefreshableApplicationContext】唯一实现的:
            ①、若已经存在beanFactory了,那就做一些清理工作(销毁单例Bean、关闭工厂)
            ②、创建了一个this.beanFactory = new DefaultListableBeanFactory();并且设置id
            ③、把旧的工厂的属性赋值给新创建的工厂:customizeBeanFactory(beanFactory)
            ④、loadBeanDefinitions(beanFactory):加载Bean定义。抽象方法,由子类去决定从哪儿去把Bean定义加载进来,实现有比如:
                    XmlWebApplicationContext:专为web设计的从xml文件里加载Bean定义(借助XmlBeanDefinitionReader)
                    ClassPathXmlApplicationContext/FileSystemXmlApplicationContext:均由父类AbstractXmlApplicationContext去实现这个方法的,也是借助XmlBeanDefinitionReader
                    AnnotationConfigWebApplicationContext:基于注解驱动的容器。借助了AnnotatedBeanDefinitionReader.register()方法加载Bean定义
                        (这里面需要注意的是:.register()只是把当前这一个Class对象registry.registerBeanDefinition()了,至于内部的@Bean、@ComponentScan扫描到的,都不是在此处注册的)
                    有必要说一句:AnnotationConfigApplicationContext是在非web环境下的容器。它虽然没有实现实现loadBeanDefinitions()抽象方法,是因为它在new对象的时候,已经调用了.register()完成配置Bean定义信息的注册了
    2)、getBeanFactory();返回刚才GenericApplicationContext创建的BeanFactory对象;
    3)、将创建的BeanFactory【DefaultListableBeanFactory】返回;
    =======到这一步截止,BeanFactory已经创建好了(只不过都还是默认配置而已),配置Bean的定义信息也注册好了=======
    
3、prepareBeanFactory(beanFactory);BeanFactory的预准备工作(对BeanFactory进行一些设置);
    1)、设置BeanFactory的类加载器、StandardBeanExpressionResolver、ResourceEditorRegistrar
    2)、添加感知后置处理器BeanPostProcessor【ApplicationContextAwareProcessor】,并设置一些忽略EnvironmentAware、EmbeddedValueResolverAware、xxxxx(因为这个处理器都一把抓了)
    3)、注册【可以解析的(表示虽然不在容器里,但还是可以直接 @Auwowired)】自动装配;我们能直接在任何组件中自动注入(@Autowired):
            BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
    5)、添加BeanPostProcessor【ApplicationListenerDetector】 检测注入进来的Bean是否是监听器
    6)、Detect a LoadTimeWeaver and prepare for weaving, if found.添加编译时的AspectJ支持:LoadTimeWeaverAwareProcessor
        (添加的支持的条件是:beanFactory.containsBean("loadTimeWeaver"))
    7)、给BeanFactory中注册一些能用的组件;

4、postProcessBeanFactory(beanFactory);BeanFactory准备工作完成后进行的后置处理工作;(由子类完成)
    一般web容器都会对应的实现此方法,比如 AbstractRefreshableWebApplicationContext:
        1)、添加感知BeanPostProcessor【ServletContextAwareProcessor】,支持到了ServletContextAware、ServletConfigAware
        2)、注册scopse:beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());当然还有SCOPE_SESSION、SCOPE_APPLICATION
        3)、向上线一样,注册【可以解析的】自动注入依赖:ServletRequest/ServletResponse/HttpSession/WebRequest
            (备注:此处放进容器的都是xxxObjectFactory类型,所以这是为何@Autowired没有线程安全问题的重要一步)
        4)、registerEnvironmentBeans:注册环境相关的Bean(使用的registerSingleton,是直接以单例Bean放到容器里面了)
            servletContext-->【ServletContext】
            servletConfig-->【ServletConfig】
            contextParameters-->【Map<String, String>】 保存有所有的init初始化参数(getInitParameter)
            contextAttributes-->【Map<String, Object>】 servletContext的所有属性(ServletContext#getAttribute(String))
            
========以上是BeanFactory的创建及预准备工作,至此准备工作完成了,那么接下来就得利用工厂干点正事了========

5、invokeBeanFactoryPostProcessors(beanFactory);执行BeanFactoryPostProcessor的方法;
    BeanFactoryPostProcessor:BeanFactory的后置处理器。此处调用,现在就表示在BeanFactory标准初始化之后执行的;
    两个接口:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor(子接口)
    1)、执行BeanFactoryPostProcessor们的方法;
    
        ===先执行BeanDefinitionRegistryPostProcessor===
        1)、获取所有的BeanDefinitionRegistryPostProcessor;(当然会最先执行我们手动set进去的Processor,但是这个一般都不会有)
        2)、先执行实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessor、
            postProcessor.postProcessBeanDefinitionRegistry(registry)
        3)、在执行实现了Ordered顺序接口的BeanDefinitionRegistryPostProcessor
        4)、最后执行没有实现任何优先级或者是顺序接口的BeanDefinitionRegistryPostProcessors
        (小细节:都会调用getBean(“name”,BeanDefinitionRegistryPostProcessor.class)方法,所以都会先实例化,才去执行的)
        
        **这里面需要特别的介绍一个处理器:`ConfigurationClassPostProcessor`,它是一个BeanDefinitionRegistryPostProcessor**
        **它会解析完成所有的@Configuration配置类,然后所有@Bean、@ComponentScan等等Bean定义都会搜集进来了,所以这一步是非常的重要的**
    
        ===再执行BeanFactoryPostProcessor的方法(顺序逻辑同上,略)===
    2)、再次检测一次添加对AspectJ的支持。为何还要检测呢?through an @Bean method registered by ConfigurationClassPostProcessor,这样我们注入了一个切面Bean,就符合条件了嘛
        
6、registerBeanPostProcessors(beanFactory);注册BeanPostProcessor(Bean的后置处理器)【 intercept bean creation】
        **不同接口类型的BeanPostProcessor;在Bean创建前后的执行时机是不一样的**
        BeanPostProcessor:BeanPostProcessor是一个工厂钩子,允许Spring框架在新创建Bean实例时对其进行定制化修改,比如填充Bean、创建代理、解析Bean内部的注解等等。。。
        DestructionAwareBeanPostProcessor:Bean销毁时候
        InstantiationAwareBeanPostProcessor:Bean初始化的时候
        SmartInstantiationAwareBeanPostProcessor:初始化增强版本:增加了一个对Bean类型预测的回调(一般是Spring内部使用,调用者还是使用InstantiationAwareBeanPostProcessor就好)
        MergedBeanDefinitionPostProcessor:合并处理Bean定义的时候的回调【该类型的处理器保存在名为internalPostProcessors的List中】、
        
        1)、获取所有的 BeanPostProcessor;后置处理器都默认可以通过PriorityOrdered、Ordered接口来执行优先级
        2)、先注册PriorityOrdered优先级接口的BeanPostProcessor;
            把每一个BeanPostProcessor;添加到BeanFactory中
            beanFactory.addBeanPostProcessor(postProcessor);
        3)、再注册Ordered接口的、最后注册没有实现任何优先级接口的、最终注册MergedBeanDefinitionPostProcessor
            (此处细节:BeanPostProcessor本身也是一个Bean,其注册之前一定先实例化,而且是分批实例化和注册。
            另外还有一个非常非常重要的一点就是阶段顺序问题:
            我们可以把BeanPostProcessor的实例化与注册分为四个阶段:
                    第一阶段applicationContext内置阶段、
                    第二阶段priorityOrdered阶段、
                    第三阶段Ordered阶段、
                    第四阶段nonOrdered阶段
            因为是分批注册,所以我们同阶段是不能拦截到同阶段的BeanPostProcessor的实例化的。举例子:
            PriorityOrdered的只能被内置阶段的比如:ApplicationContextAwareProcessor(可以注入啦)/ApplicationListenerDetector(可以接受事件啦)这种拦截
            而:Ordered就可以被    内置的、PriorityOrdered都拦截到了
            。。。 以此类推。。。
            
            所以我们的BeanPostProcessor是可以@Autowired 比如Service、Dao来做一些事的。单思,但是一定要【注意避免BeanPostProcessor启动时的“误伤”陷阱】,什么意思?大概解释一下如下:
                可能由于你的Processor依赖于某个@Bean,从而让它提前实例化了,然后就很可能错过了后面一些BeanPostProcessor的处理,造成“误伤”
                (SpringBoot中使用Shiro、Spring-Cache的时候,使用不当会出现这样的问题)
    
        6)、这一步非常有意思:moving it to the end of the processor chain。它的又注册了一次,作用是把这个探测器移动到处理器的底部,最后一个(显然,最后一个是为了不要放过任何Bean)
            (小细节:可能有小伙伴疑问,这里也是new出来,这这样容器内不就有两个探测器对象了吗?气其实不然,ApplicationListenerDetector它重写了hashCode方法,且只和应用applicationContext有关)
            return ObjectUtils.nullSafeHashCode(this.applicationContext);所以对它执行remove的时候,会被当作同一个对象处理,能把老的移除成功添加新的的

7、initMessageSource();初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
        1)、看容器中是否有id为messageSource的,类型是MessageSource的组件
            如果有赋值给messageSource,如果没有自己创建一个DelegatingMessageSource;
                MessageSource:取出国际化配置文件中的某个key的值;能按照区域信息获取;
        2)、把创建好的MessageSource注册在容器中,以后获取国际化配置文件的值的时候,可以自动注入MessageSource
        beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource)
        
8、initApplicationEventMulticaster();初始化事件派发器;
        1)、从BeanFactory中获取applicationEventMulticaster的ApplicationEventMulticaster;
        2)、如果上一步没有配置;创建一个SimpleApplicationEventMulticaster,将创建的ApplicationEventMulticaster添加到BeanFactory中
        
9、onRefresh();留给子容器(子类) 容器刷新的时候做些事
        AbstractRefreshableWebApplicationContext:this.themeSource = UiApplicationContextUtils.initThemeSource(this);
        
10、registerListeners();把容器中将所有项目里面的ApplicationListener注册进来;
        1、拿到容器里所有的Bean定义的名字,类型为ApplicationListener,然后添加进来
            getApplicationEventMulticaster().addApplicationListener(listener);
        2、派发之前步骤产生的事件(早期事件)
        (细节:此处只是把Bean的名字放进去,Bean还没有实例化哦~~~~)

11、finishBeanFactoryInitialization(beanFactory);初始化所有剩下的单实例bean;这应该是最核心的一步了
    1)、为容器初始化ConversionService(容器若没有就不用初始化了,依然采用getBean()初始化的) 提供转换服务
    2)、若没有设置值解析器,那就注册一个默认的值解析器(lambda表示的匿名处理)
    3)、实例化LoadTimeWeaverAware(若存在)
    4)、清空临时类加载器:beanFactory.setTempClassLoader(null)
    5)、缓存(快照)下当前所有的Bean定义信息 beanFactory.freezeConfiguration();
    ==== 更精确的是说是根据Bean的定义信息:beanDefinitionNames来实例化、初始化剩余的Bean ====
    6)、beanFactory.preInstantiateSingletons();初始化后剩下的单实例bean(过程这里就不详说了)
    
12、finishRefresh();完成BeanFactory的初始化创建工作;IOC容器就创建完成
        0)、clearResourceCaches(); (Spring5.0才有)
        1)、initLifecycleProcessor();初始化和生命周期有关的后置处理器;从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】;如果没有new DefaultLifecycleProcessor();
            关于Lifecycle接口的使用,也专门讲解过,这里不聊了
        2)、getLifecycleProcessor().onRefresh();  相当于上面刚注册,下面就调用了
        3)、publishEvent(new ContextRefreshedEvent(this));发布容器刷新完成事件;
        4)、liveBeansView.registerApplicationContext(this); 和MBean相关,略
    
    ======总结===========
    1)、Spring容器在启动的时候,先会保存所有注册进来的Bean的定义信息(可以有N种方式);
        1)、xml注册bean;<bean>
        2)、注解注册Bean;@Service、@Component、@Bean、xxx
    2)、Spring容器会合适的时机创建这些Bean
        1)、用到这个bean的时候;利用getBean创建bean;创建好以后保存在容器中;
        2)、统一创建剩下所有的bean的时候;finishBeanFactoryInitialization();
    3)、后置处理器;BeanPostProcessor
        1)、每一个bean创建完成,都会使用各种后置处理器进行处理;来增强bean的功能;
            AutowiredAnnotationBeanPostProcessor:处理自动注入
            AnnotationAwareAspectJAutoProxyCreator:来做AOP功能;
            xxx....
            增强的功能注解:
            AsyncAnnotationBeanPostProcessor
            ....
    4)、事件驱动模型;
        ApplicationListener;事件监听;
        ApplicationEventMulticaster;事件派发:
 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值