介绍
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流程图
说明
-> 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
- Spring把各种类型的文件都可以叫做Resource,只不过对于Spring开发者来说,Resource大多都是xml文件。
- Resource 接口是具体资源访问策略的抽象,也是所有资源访问类所实现的接口。Resource 接口本身没有提供访问任何底层资源的实现逻辑,针对不同的底层资源,Spring 将会提供不同的 Resource 实现类,不同的实现类负责不同的资源访问逻辑。
ResourceLoader
字面意思是Resource数据的加载器
PathMatchingResourcePatternResolver
返回资源加载器用于资源位置。可以检查ResourcePatternResolver接口并进行相应的转换,以便为给定的资源模式加载多个资源
BeanFactoryPostProcessor
给使用者留下的扩展点,可以修改,新增BeanDefinition。因为此时所有的BeanDefinition已经加载,但是没有Bean被创建。一般用在需要覆盖或替换Bean的属性时。
该扩展点提供了两个方法:
BeanPostProcessor
是在Bean新创建后,未初始化前调用的。例如在InitializingBean的afterPropertiesSet前,或则自定义的init-method前。
在Bean初始化后,调用方法postProcessAfterInitialization。
ApplicationContext
ApplicationContext 丰富了BeanFactory的功能,
继承了下面几个类
- EnvironmentCapable,
- ListableBeanFactory,
- HierarchicalBeanFactory,
- MessageSource,
- ApplicationEventPublisher,
- ResourcePatternResolver
AbstractApplicationContext 实现了ConfigurableApplicationContext
注:ConfigurableApplicationContext 实现了ApplicationContext, Lifecycle, Closeable
AbstractApplicationContext 这个类干的活太多了,核心核心,这里多说一句,spring很多逻辑都放到了抽象类里面,当你看这些代码的时候,找不到调用关系,可以去父类里面看看
ClassPathXmlApplicationContext
ClassPathXmlApplicationContext的构造方法里面干了一些事
这里面调用了AbstractApplicationContext的refresh()方法
BeanDefinitionReader
BeanDefinitionReader不能直接加载配置文件,需要把配置文件封装成Resource,
将Resource转换成BeanDefinition的各种工鞥
然后才能调用重载方法loadBeanDefinitions()
BeanDefinitionReader只是一个标准的bean definition读取器接口,他提供了几个标准方法:
- BeanDefinitionRegistry getRegistry();
- ResourceLoader getResourceLoader();
- ClassLoader getBeanClassLoader();
- BeanNameGenerator getBeanNameGenerator();
- int loadBeanDefinitions(Resource resource)
loadBeanDefinitions有多个重载方法,但是功能都是一样,用于加载bean的定义
首先是getRegistry用于获取一个bean注册的容器类,BeanDefinitionRegistry在这里也是一个接口,具体到类就要提到DefaultListableBeanFactory,
DefaultListableBeanFactory
是整个bean加载的核心部分,是spring注册及加载bean的默认实现
DefaultListableBeanFactory 继承了 AbstractAutowireCapableBeanFactory,并且实现了ConfigurableListableBeanFactory、BeanDefinitionRegistry接口
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的解析(比如、、标签),对于扩展的标签会交给不同的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做一些框架层面的东西