美文网首页Spring源码
[Spring] IOC启动顺序

[Spring] IOC启动顺序

作者: 程序员驿站 | 来源:发表于2018-03-21 14:05 被阅读320次

介绍

IOC整个流程大致分为下面几步:

  • IOC容器启动入口是AbstractApplicationContext#在refresh
  • 通过ResourceLoader来解析成资源对象(这里Spring将所有资源都抽象成Resource)
  • 创建默认的Bean注册器DefaultListableBeanFactory
  • BeanDefinitionReader主要是解析和Bean的注册
  • XmlBeanDefinitionReader通过它来解析xml配置中的bean定义,委托BeanDefinition
  • BeanDefinitionRegistry 将BeanDefinition保存到ConcurrentHashMap中

详细说明

那我们就从ContextLoaderListener说起,ContextLoaderListener实现了ServletContextListener接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。在ContextLoaderListener又继承了ContextLoader,所以整个加载配置过程由ContextLoader来完成。

在web容器启动的时候会调用contextInitialized方法,contextInitialized实际调用ContextLoader#initWebApplicationContext方法,那initWebApplicationContext都做了哪些工作:

  • createWebApplicationContext,初始化XmlWebApplicationContext
  • 将ApplicationContext注册到当前servletContext
  • 最后XmlWebApplicationContext#refresh()刷新整个容器

refresh流程图

diagram-1438971934839698549.png

说明

-> prepareRefresh()

--
-> ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    -> AbstractRefreshableApplicationContext#refreshBeanFactory
        -> createBeanFactory()
            -> 创建 DefaultListableBeanFactory(ListableBeanFactory和BeanDefinitionRegistry接口的默认实现:一个基于bean定义对象的成熟bean工厂)
        -> 配置bean工厂
        -> loadBeanDefinitions
            -> 子类AbstractXmlApplicationContext#loadBeanDefinitions
                -> new XmlBeanDefinitionReader();(创建beanDefault阅读器)
                -> 设置环境
                -> 定义resourceLoader(资源加载器)
                -> 给子类留的入口为了初始化beanDefinition阅读器
                -> loadBeanDefinitions 加载bean
                    -> loadBeanDefinitions(XmlBeanDefinitionReader reader)  
                        -> AbstractBeanDefinitionReader#loadBeanDefinitions(reader 根据配置文件加载Bean)
                            -> getResourceLoader()
                            -> XmlBeanDefinitionReader#loadBeanDefinitions(从配置文件读取)
                            -> XmlBeanDefinitionReader#doLoadBeanDefinitions
                                ->doLoadDocument
                                    ->DefaultDocumentLoader#loadDocument
                                    -> DefaultDocumentLoader#createDocumentBuilderFactory
                                    -> DocumentBuilder builder=createDocumentBuilder
                                    -> builder 解析xml文件
                                ->registerBeanDefinitions
                                    -> DefaultBeanDefinitionDocumentReader=createBeanDefinitionDocumentReader
                                    -> 获取已经注册bean的个数
                                    -> createReaderContext
                                    -> DefaultBeanDefinitionDocumentReader#
                                        ->doRegisterBeanDefinitions
                                        -> createDelegate
                                            -> BeanDefinitionParserDelegate
                                        -> preProcessXml 处理前 (留给子类实现)
                                        -> parseBeanDefinitions 
                                            -> parseDefaultElement(这里面根据Element的name去使用不同的解析)
                                                -> processBeanDefinition 这里主要解析下这个
                                                    -> BeanDefinitionParserDelegate解析xml为BeanDefinitionHolder
                                                    -> decorateBeanDefinitionIfRequired装饰该bean 依赖的子类的
                                                    -> BeanDefinitionReaderUtils.registerBeanDefinition 向DefaultListableBeanFactory注册beanDefinition
                                                    将beanDefinition保存到DefaultListableBeanFactory#beanDefinitionMap
                                                    -> fireComponentRegistered 发送注册事件
                                            -> BeanDefinitionParserDelegate#parseCustomElement -- 这里是处理继承NamespaceHandler接口的,实际上就是spring自定义标签解析

                                        -> postProcessXml 处理后 (留给子类实现)
                                        
-> prepareBeanFactory()  配置工厂的标准上下文特征 -如上下文的ClassLoader和后处理器
    ->beanFactory.setBeanClassLoader
    -> setBeanExpressionResolver 设置表达式编辑器
    -> addPropertyEditorRegistrar 
    为给定的ResourceLoader和PropertyResolver创建一个新的ResourceEditorRegistrar
    -> addBeanPostProcessor bean工厂 配置一些回调类  重点说下这块,因为我们经常实现一些类被spring 回调
        -> ApplicationContextAwareProcessor,这个Processor的作用在于为实现Aware接口的bean调用该Aware接口定义的方法,并传入对应的参数
    -> ignoreDependencyInterface 设置一些忽略的接口
    -> registerResolvableDependency
    -> addBeanPostProcessor 为什么这里还有一个呢,为什么不放到一起呢
        -> ApplicationListenerDetector
    -> setTempClassLoader
    -> registerSingleton
    -> addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)
    -> setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()))
    -> registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment())
    -> registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties())
    -> registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment())
->postProcessBeanFactory()
    -> addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig))
    -> ignoreDependencyInterface(ServletContextAware.class)
    -> ignoreDependencyInterface(ServletConfigAware.class)
    -> WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
    -> WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
-> invokeBeanFactoryPostProcessors (实例化并调用所有已注册的BeanFactoryPostProcessor bean,如果给定,则考虑显式的顺序。)
必须在单例实例化之前调用
-> registerBeanPostProcessors 重点
-> initMessageSource()
-> onRefresh()
-> registerListeners()
-> finishBeanFactoryInitialization(beanFactory)
-> finishRefresh()

组件

Resource

  1. Spring把各种类型的文件都可以叫做Resource,只不过对于Spring开发者来说,Resource大多都是xml文件。
  2. Resource 接口是具体资源访问策略的抽象,也是所有资源访问类所实现的接口。Resource 接口本身没有提供访问任何底层资源的实现逻辑,针对不同的底层资源,Spring 将会提供不同的 Resource 实现类,不同的实现类负责不同的资源访问逻辑。

ResourceLoader

字面意思是Resource数据的加载器

PathMatchingResourcePatternResolver

返回资源加载器用于资源位置。可以检查ResourcePatternResolver接口并进行相应的转换,以便为给定的资源模式加载多个资源

BeanFactoryPostProcessor

给使用者留下的扩展点,可以修改,新增BeanDefinition。因为此时所有的BeanDefinition已经加载,但是没有Bean被创建。一般用在需要覆盖或替换Bean的属性时。
该扩展点提供了两个方法:

BeanPostProcessor

是在Bean新创建后,未初始化前调用的。例如在InitializingBean的afterPropertiesSet前,或则自定义的init-method前。
在Bean初始化后,调用方法postProcessAfterInitialization。

ApplicationContext

ApplicationContext 丰富了BeanFactory的功能,
继承了下面几个类

  1. EnvironmentCapable,
  2. ListableBeanFactory,
  3. HierarchicalBeanFactory,
  4. MessageSource,
  5. ApplicationEventPublisher,
  6. ResourcePatternResolver

AbstractApplicationContext 实现了ConfigurableApplicationContext

注:ConfigurableApplicationContext 实现了ApplicationContext, Lifecycle, Closeable
AbstractApplicationContext 这个类干的活太多了,核心核心,这里多说一句,spring很多逻辑都放到了抽象类里面,当你看这些代码的时候,找不到调用关系,可以去父类里面看看

ClassPathXmlApplicationContext

ClassPathXmlApplicationContext的构造方法里面干了一些事
这里面调用了AbstractApplicationContext的refresh()方法

BeanDefinitionReader

BeanDefinitionReader不能直接加载配置文件,需要把配置文件封装成Resource,
将Resource转换成BeanDefinition的各种工鞥
然后才能调用重载方法loadBeanDefinitions()

BeanDefinitionReader只是一个标准的bean definition读取器接口,他提供了几个标准方法:

  1. BeanDefinitionRegistry getRegistry();
  2. ResourceLoader getResourceLoader();
  3. ClassLoader getBeanClassLoader();
  4. BeanNameGenerator getBeanNameGenerator();
  5. int loadBeanDefinitions(Resource resource)
    loadBeanDefinitions有多个重载方法,但是功能都是一样,用于加载bean的定义

首先是getRegistry用于获取一个bean注册的容器类,BeanDefinitionRegistry在这里也是一个接口,具体到类就要提到DefaultListableBeanFactory,

DefaultListableBeanFactory

是整个bean加载的核心部分,是spring注册及加载bean的默认实现
DefaultListableBeanFactory 继承了 AbstractAutowireCapableBeanFactory,并且实现了ConfigurableListableBeanFactory、BeanDefinitionRegistry接口

屏幕快照 2018-05-15 下午7.36.55.png

XmlWebApplicationContext

//通过XmlBeanDefinitionReader加载bean定义
loadBeanDefinitions(DefaultListableBeanFactory beanFactory)

BeanDefinitionRegistry

作用:用于存放bean定义的注册表的接口,例如RootBeanDefinition和ChildBeanDefinition实例。通常由内部使用AbstractBeanDefinition层次结构的BeanFactories实现.
这是Spring的bean工厂包中唯一封装了bean定义注册的接口。标准的BeanFactory接口仅涵盖对完全配置的工厂实例的访问

DocumentLoader

定义从资源文件加载到转换为Document的功能

BeanDefinitionDocumentReader

实现了BeanDefinitionDocumentReader接口,DefaultBeanDefinitionDocumentReader并不负责任何具体的bean解析,它面向的是xml Document对象,根据其元素的命名空间和名称,起一个类似路由的作用((不过,命名空间的判断,也是委托给delegate来做的),它跟BeanDefinitionParserDelegate协同合作,把解析任务交接BeanDefinitionParserDelegate来做

BeanDefinitionParserDelegate

完成具体Bean的解析(比如<bean>、<import>、<alias>标签),对于扩展的标签会交给不同的NamespaceHandler跟BeanDefinitionParser来解析

BeanDefinitionParser

解析配置文件成相应的BeanDefinition(<context:component-scan>,<aop:config>等标签都是又不同的BeanDefinitionParser来解析),一般在NamespaceHandler中使用。Spring也为自定义BeanDefinitionParser提供了很多支持,在一些抽象类的基础上添加少量功能即可满足大部分需求。

NamespaceHandler

要解析自定义的bean就要通过自己所实现的NamespaceHandler来进行解析。比如定义了http://www.springframework.org/schema/osgi=org.springframework.osgi.config.OsgiNamespaceHandler,那么在碰到osgi的scheme的时候就会去调用OsgiNamespaceHandler来进行解析; 在对于普通的扩展需求来说,只要让自己的Handler继承NamespaceHandlerSupport并实现 init()方法 就好了,对于特殊的扩展需求 则可以自己 来实现NamespaceHandler。

总结

  • Spring的代码结构非常清晰
  • 每个类的职责非常单一,我们写代码也尽量让每个类的只干一件事
  • 我们可以基于BeanPostProcessor做一些框架层面的东西

相关文章

网友评论

    本文标题:[Spring] IOC启动顺序

    本文链接:https://www.haomeiwen.com/subject/yqlgqftx.html