Spring 对于程序员说来说都不陌生; 作为一个强大的开源技术, 帮助我们能够更好的进行项目的开发与维护
上次在 Spring 的启动过程文章中对 Spring 的启动过程做了一个较为详细的说明和分析那么在实际的过程中, Spring 的启动实际上就是 Spring 容器的初始化过程本文将从源码的角度结合自己断点执行过程中保留的现场来分析一下容器的刷新过程(主要分析前几个方法, 后面几个会分开来说)
Spring 的启动是通过 ContextLoaderListener 来进行的, 在 ContextLoaderListener 中通过委托父类 ContextLoader 的 initwebApplicationContext 来完成具体的初始化过程具体的启动过程可以看下之前的那篇文章
在 initWebApplicationContext 方法是用来创建容器的, 核心代码如下:
image.png
今天主要来看 configureAndRefreshWebApplicationContext 方法中最后的 wac.refresh()到底发生了哪些事;
image.png
1obtainFreshBeanFactory:BeanFactory 的刷新和创建
refresh()方法主要为 IoC 容器 Bean 的生命周期管理提供条件, Spring IoC 容器载入 Bean 定义资源文件从其子类容器的 refreshBeanFactory()方法启动, 所以整个 refresh()中 ConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory(); 这句以后代码的都是注册容器的信息源和生命周期事件, 载入过程就是从这句代码启动
AbstractApplicationContext 的 obtainFreshBeanFactory()方法调用子类容器的 refreshBeanFactory()方法, 启动容器载入 Bean 定义资源文件的过程
refresh()方法的作用是: 在创建 IoC 容器前, 如果已经有容器存在, 则需要把已有的容器销毁和关闭, 以保证在 refresh 之后使用的是新建立起来的 IoC 容器 refresh 的作用类似于对 IoC 容器的重启, 在新建立好的容器中对容器进行初始化, 对 Bean 定义资源进行载入
和 refreshBeanFactory 方法类似, 载入 Bean 定义的方法 loadBeanDefinitions 也使用了委派模式, 在 AbstractRefreshableApplicationContext 类中只定义了抽象方法, 具体的实现调用子类容器中的方法实现
// 通知子类去刷新内部 bean 工厂
image.png
再来看 refreshBeanFactory
此实现执行该上下文的底层 bean 工厂的实际刷新, 关闭以前的 bean 工厂(如果有的话), 并为上下文生命周期的下一阶段初始化一个新的 bean 工厂
image.png
- customizeBeanFactory(DefaultListableBeanFactory beanFactory)
- /**
- // 通过当前上下文来自定义内部 bean 工厂 < br>
- * Customize the internal bean factory used by this context.
- * Called for each {@link #refresh()} attempt.
- * <p>The default implementation applies this context's
- * {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
- * and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings,
- * if specified. Can be overridden in subclasses to customize any of
- * {@link DefaultListableBeanFactory}'s settings.
- * @param beanFactory the newly created bean factory for this context
- * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
- * @see DefaultListableBeanFactory#setAllowCircularReferences
- * @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
- * @see DefaultListableBeanFactory#setAllowEagerClassLoading
- */
- protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
- if (this.allowBeanDefinitionOverriding != null) {
- beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
- }
- if (this.allowCircularReferences != null) {
- beanFactory.setAllowCircularReferences(this.allowCircularReferences);
- }
- }
XmlWebApplicationContext 类中 loadBeanDefinitions(beanFactory)
- @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException,
- IOException {
- // Create a new XmlBeanDefinitionReader for the given BeanFactory.
- XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
- // Configure the bean definition reader with this context's
- // resource loading environment.
- beanDefinitionReader.setEnvironment(getEnvironment());
- beanDefinitionReader.setResourceLoader(this);
- beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
- // Allow a subclass to provide custom initialization of the reader,
- // then proceed with actually loading the bean definitions.
- initBeanDefinitionReader(beanDefinitionReader);
- loadBeanDefinitions(beanDefinitionReader);
- }
AbstractApplicationContext 调用 loadBeanDefinitions(DefaultListableBeanFactory beanFactory) , 此方法根据首先创建 XmlBeanDefinitionReader 对象, 然后配置该对象的上下文和资源加载环境, 同时调用子类实现的 initBeanDefinitionReader 对 XmlBeanDefinitionReader 进行个性化配置, 最近后入到 initBeanDefinitionReader(beanDefinitionReader)的调用:
据给定的 BeanFactory 创建 XmlBeanDefinitionReader 对象
配置 beanDefinitionReader 的上下文和资源加载环境
用子类实现的 initBeanDefinitionReader 对 XmlBeanDefinitionReader 进行个性化配置 initBeanDefinitionReader(beanDefinitionReader);
调用载入 Bean 定义的方法, 在当前类中只定义了抽象的 loadBeanDefinitions 方法, 具体的实现调用子类容器
装载 bean 定义通过 XmlBeanDefinitionReader
- // Create a new XmlBeanDefinitionReader for the given BeanFactory. 通过给定的 bean 工厂创建一个新的 XmlBeanDefinitionReader
- 1.XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
2. 使用上下文的资源加载环境配置 bean 定义读取器
- beanDefinitionReader.setEnvironment(getEnvironment());
- beanDefinitionReader.setResourceLoader(this);
- beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
3. 允许子类提供 reader 的自定义初始化, 然后继续实际加载 bean 定义
- // 通过制定的 XmlBeanDefinitionReader 来载入 beandefinitionReader
- initBeanDefinitionReader(beanDefinitionReader)
- // 通过制定的 XmlBeanDefinitionReader 来载入 bean definitions
- loadBeanDefinitions(beanDefinitionReader)
AbstractApplicationContext 调用 loadBeanDefinitions(beanDefinitionReader), 这个方法是取得资源或资源路径然后通过传入的 reader 去加载 BeanDefinitions
image.png
2loadBeanDefinitions
目前使用 Spring 的配置都是基于 XML 的, 因此使用 XmlBeanDefinitionReader 中的 loadBeanDefinitions 方法
image.png
image.png
看 doLoadBeanDefinitions, 这个就是具体的读取文件配置, 然后注册成 Bean
image.png
image.png
3prepareBeanFactory
配置工厂的标准上下文特性, 如上下文的类装载器和后处理器
image.png
告诉内部 bean 工厂使用上下文的类装入器等
上下文回调配置 bean 工厂
BeanFactory 接口未登记为普通工厂的解析式 MessageSource 登记 (为自动装配创建) 作为一个 Bean
如果创建; 就去寻找 LoadTimeWeaver, 然后准备组织
注册默认环境 bean
通过断点来看下当前的 beanFactory
image.png
image.png
继续执行...
image.png
image.png
beanDefinitionMap
image.png
manualSingletonNames
image.png
4postProcessBeanFactory
注册 web 特性的全局域
1).registerWebApplicationScopes
image.png
注册具有 web 特性的域; 包括:"request", "session", "globalSession", "application"
image.png
看下存储结构:
image.png
registerScope 方法
image.png
2).registerEnvironmentBeans
注册 web 特性 环境 bean(contextparametersContextAttribute)与给定的 WebApplicationContext 使用 BeanFactory
1.servletContext
image.png
2.servletConfig
image.png
3.registerSingleton
image.png
image.png
image.png
这里是找到了我们默认的配置文件参数:
image.png
beanName=contextParameters
image.png
image.png
image.png
最后是将 contextAttributes 放入; contextAttributes 中包含的属性值比较多, 具体如下面所示:
image.png
主要包括:
- javax.servlet.context.tempdir,
- org.apache.catalina.resources, org.springframework.web.context.support.ServletContextScope, org.apache.tomcat.util.scan.MergedWebXml,
- org.apache.tomcat.InstanceManager,
- org.apache.catalina.jsp_classpath,
- javax.websocket.server.ServerContainer,
- org.apache.tomcat.JarScanner
image.png
这里是把需要的东西全部载入进来了, 有很多就不贴了(mime-mapping)....
5invokeBeanFactoryPostProcessors
BeanDefinitionRegistryPostProcessor 实例化: 标准 BeanFactoryPostProcessor 的扩展, BeanFactoryPostProcessor 的作用是用来进一步定义注册的 BeanDefinition,IoC 容器本质就是 Bean 管理, 所以 BeanFactoryPostProcessor 本身也是 Bean, 要对 BeanFactoryPostProcessor 的 BeanDefinition 进一步定义就通过 BeanDefinitionRegistryPostProcessor 进行注册, BeanDefinitionRegistryPostProcessor 及其子类是 Ioc 容器最实例化的一类 Bean 它们在 ConfigurableApplicationContext(ApplicationContext 子接口)实现类调用 refresh()方法调用 invokeBeanFactoryPostProcessors(beanFactory); 方法时就被实例化
OK, 今天关于这部分的分析就到此结束了, 后面的过程会在下一篇 Spring 系列文章中继续来讲 refresh 中的过程
来源: http://www.jianshu.com/p/80d5d04a37ec