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配置默认环境