1、上面那句代码有个文件叫applicationContext.xml
, 这是个资源文件,由于我们的bean
都在里边进行配置定义,那 Spring 总得对这个文件进行读取并解析
吧!所以 Spring 中有个模块叫Resource
模块,顾名思义,就是资源
嘛!用于对所有资源xml、txt、property
等文件资源的抽象。关于对Resource
的更多知识,可以参考下边两篇文章:
2、上面讲了 Spring 框架对各种资源的抽象采用了策略模式
,那么问题来了,现在表示资源的东西有了,那么是怎么把该资源加载进来呢?于是就有了下面的ResourceLoader
组件,该组件负责对 Spring 资源的加载,资源指的是xml
、properties
等文件资源,返回一个对应类型的Resource
对象。。UML 图如下:
3、上面两点讲到了,好!既然我们拥有了加载器ResourceLoader
,也拥有了对资源的描述Resource
, 但是我们在 xml 文件中声明的<bean/>
标签在 Spring 又是怎么表示的呢?注意这里只是说对bean
的定义,而不是说如何将<bean/>
转换为bean
对象。我想应该不难理解吧!就像你想表示一个学生Student
,那么你在程序中肯定要声明一个类Student
吧!至于学生数据是从excel
导入,或者程序运行时new
出来,或者从xml
中加载进来这些都不重要,重要的是你要有一个将现实中的实体表示为程序中的对象的东西,所以<bean/>
也需要在 Spring 中做一个定义!于是就引入一个叫BeanDefinition
的组件,UML 图如下:
4、有了加载器ResourceLoader
,也拥有了对资源的描述Resource
,也有了对bean
的定义,我们不禁要问,我们的Resource
资源是怎么转成我们的BeanDefinition
的呢? 因此就引入了BeanDefinitionReader
组件, Reader 嘛!就是一种读取机制,UML 图如下:
5、好了!基本上所有组件都快齐全了!对了,还有一个组件,你有了BeanDefinition
后,你还必须将它们注册到工厂中去,所以当你使用getBean()
方法时工厂才知道返回什么给你。还有一个问题,既然要保存注册这些bean
, 那肯定要有个数据结构充当容器吧!没错,就是一个Map
, 下面贴出BeanDefinitionRegistry
的一个实现,叫SimpleBeanDefinitionRegistry
的源码图:
6、前面说的 5 个点基本上可以看出ApplicationContext
上下文基本直接或间接贯穿所有的部分,因此我们一般称之为容器
,除此之外,ApplicationContext
还拥有除了bean容器
这种角色外,还包括了获取整个程序运行的环境参数等信息(比如 JDK 版本,jre 等),其实这部分 Spring 也做了对应的封装,称之为Enviroment
, 下面就跟着小编的 eclipse, 一起 debug 下容器的初始化工程吧!
package com.wokao666; public class Student { private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Student(int id, String name, int age) { super(); this.id = id; this.name = name; this.age = age; } public Student() { super(); } @Override public String toString() { return "Student [id=" id ", ]"; } }
<bean id="stu1" class="com.wokao666.Student"> <property ></property> <property ></property> <property ></property> </bean> <bean id="stu2" class="com.wokao666.Student"> <property ></property> <property ></property> <property ></property> </bean>
/** * Set the config locations for this application context.//未应用上下文设置资源路径 * <p>If not set, the implementation may use a default as appropriate.//如果未设置,则实现可以根据需要使用默认值。 */ public void setConfigLocations(String... locations) { if (locations != null) {//非空 Assert.noNullElements(locations, "Config locations must not be null");//断言保证locations的每个元素都不为null this.configLocations = new String[locations.length]; for (int i = 0; i < locations.length; i ) { this.configLocations[i] = resolvePath(locations[i]).trim();//去空格,很好奇resolvePath做了什么事情? } } else { this.configLocations = null; } }
/** * 解析给定的资源路径,必要时用相应的环境属性值替换占位符,应用于资源路径配置。 * Resolve the given path, replacing placeholders with corresponding * environment property values if necessary. Applied to config locations. * @param path the original file path * @return the resolved file path * @see org.springframework.core.env.Environment#resolveRequiredPlaceholders(String) */ protected String resolvePath(String path) { return getEnvironment().resolveRequiredPlaceholders(path); }
/** * {@inheritDoc} * <p>If {@code null}, a new environment will be initialized via * {@link #createEnvironment()}. */ @Override public ConfigurableEnvironment getEnvironment() { if (this.environment == null) { this.environment = createEnvironment(); } return this.environment; }
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 刷新前准备工作,包括设置启动时间,是否激活标识位,初始化属性源(property source)配置 prepareRefresh(); // 创建beanFactory(过程是根据xml为每个bean生成BeanDefinition并注册到生成的beanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //准备创建好的beanFactory(给beanFactory设置ClassLoader,设置SpEL表达式解析器,设置类型转化器【能将xml String类型转成相应对象】, //增加内置ApplicationContextAwareProcessor对象,忽略各种Aware对象,注册各种内置的对账对象【BeanFactory,ApplicationContext】等, //注册AOP相关的一些东西,注册环境相关的一些bean prepareBeanFactory(beanFactory); try { // 模板方法,为容器某些子类扩展功能所用(工厂后处理器)这里可以参考BeanFactoryPostProcessor接口的postProcessBeanFactory方法 postProcessBeanFactory(beanFactory); // 调用所有BeanFactoryPostProcessor注册为Bean invokeBeanFactoryPostProcessors(beanFactory); // 注册所有实现了BeanPostProcessor接口的Bean registerBeanPostProcessors(beanFactory); // 初始化MessageSource,和国际化相关 initMessageSource(); // 初始化容器事件传播器 initApplicationEventMulticaster(); // 调用容器子类某些特殊Bean的初始化,模板方法 onRefresh(); // 为事件传播器注册监听器 registerListeners(); // 初始化所有剩余的bean(普通bean) finishBeanFactoryInitialization(beanFactory); // 初始化容器的生命周期事件处理器,并发布容器的生命周期事件 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " "cancelling refresh attempt: " ex); } // 销毁已创建的bean destroyBeans(); // 重置`active`标志 cancelRefresh(ex); throw ex; } finally { //重置一些缓存 resetCommonCaches(); } } }
/** * Prepare this context for refreshing, setting its startup date and * active flag as well as performing any initialization of property sources. */ protected void prepareRefresh() { this.startupDate = System.currentTimeMillis();//设置容器启动时间 this.closed.set(false);//容器关闭标志,是否关闭? this.active.set(true);//容器激活标志,是否激活? if (logger.isInfoEnabled()) {//运行到这里,控制台就会打印当前容器的信息 logger.info("Refreshing " this); } // 空方法,由子类覆盖实现,初始化容器上下文中的property文件 initPropertySources(); //验证标记为必需的所有属性均可解析,请参阅ConfigurablePropertyResolver#setRequiredProperties getEnvironment().validateRequiredProperties(); //允许收集早期的ApplicationEvents,一旦多播器可用,即可发布... this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>(); }
三月 22, 2018 4:21:13 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@96532d6: startup date [Thu Mar 22 16:21:09 CST 2018]; root of context hierarchy
/** * 告诉子类刷新内部bean工厂(子类是指AbstractApplicationContext的子类,我们使用的是ClassPathXmlApplicationContext) * Tell the subclass to refresh the internal bean factory. */ protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory();//刷新Bean工厂,如果已经存在Bean工厂,那就关闭并销毁,再创建一个新的bean工厂 ConfigurableListableBeanFactory beanFactory = getBeanFactory();//获取新创建的Bean工厂 if (logger.isDebugEnabled()) { logger.debug("Bean factory for " getDisplayName() ": " beanFactory);//控制台打印 } return beanFactory; }
/** * 该实现执行该上下文的基础Bean工厂的实际刷新,关闭以前的Bean工厂(如果有的话)以及为该上下文的生命周期的下一阶段初始化新鲜的Bean工厂。 * This implementation performs an actual refresh of this context's underlying * bean factory, shutting down the previous bean factory (if any) and * initializing a fresh bean factory for the next phase of the context's lifecycle. */ @Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) {//如果已有bean工厂 destroyBeans();//销毁 closeBeanFactory();//关闭 } try { DefaultListableBeanFactory beanFactory = createBeanFactory();//创建一个新的bean工厂 beanFactory.setSerializationId(getId());//为序列化目的指定一个id,如果需要,可以将此BeanFactory从此id反序列化回BeanFactory对象。 //定制容器,设置启动参数(bean可覆盖、循环引用),开启注解自动装配 customizeBeanFactory(beanFactory); ////将所有BeanDefinition载入beanFactory中,此处依旧是模板方法,具体由子类实现 loadBeanDefinitions(beanFactory); //beanFactory同步赋值 synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " getDisplayName(), ex); } }
/** * 使用XmlBeanDefinitionReader来加载beandefnition,之前说过使用reader机制加载Resource资源变为BeanDefinition对象 * Loads the bean definitions via an XmlBeanDefinitionReader. * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader * @see #initBeanDefinitionReader * @see #loadBeanDefinitions */ @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // 创建XmlBeanDefinitionReader对象 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // 使用当前上下文Enviroment中的Resource配置beanDefinitionReader,因为beanDefinitionReader要将Resource解析成BeanDefinition嘛! beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); //初始化这个reader initBeanDefinitionReader(beanDefinitionReader); //将beandefinition注册到工厂中(这一步就是将bean保存到Map中) loadBeanDefinitions(beanDefinitionReader); }
三月 22, 2018 5:09:40 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [applicationContext.xml]
//设置bean类加载器 //设置Spring语言表达式(SpEL)解析器 //扫描ApplicationContextAware bean //注册类加载期类型切面织入(AOP)LoadTimeWeaver //为各种加载进入beanFactory的bean配置默认环境