前言
上一篇spring源码解读系列(一)我们整体介绍spring工厂创建,完成bean初始化的过程,并介绍了开始初始化前的准备工作的两个方法,本篇文章我们进入Spring最核心的方法org.springframework.context.support.AbstractApplicationContext#refresh,先整体熟悉一下此方法的主要工作,然后我们再对其中调用到的核心方法以及扩展点逐一解析。
一、核心方法AbstractApplicationContext.refresh
直接进入源码,逐行理解
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
/**
* 做容器刷新前的准备工作
* 1、设置容器的启动时间
* 2、设置活跃状态为true
* 3、设置关闭状态为false
* 4、获取Environment对象,并加载当前系统的属性值到Environment对象中
* 5、准备监听器和事件的集合对象,默认为空的集合
*/
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 创建容器对象:DefaultListableBeanFactory
// 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinition
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// beanFactory的准备工作,对各种属性进行填充
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 调用各种beanFactory处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注册bean处理器,这里只是注册功能,真正调用的是getBean方法
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 为上下文初始化message源,即不同语言的消息体,国际化处理,在springmvc的时候通过国际化的代码重点讲
initMessageSource();
// Initialize event multicaster for this context.
// 初始化事件监听多路广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 留给子类来初始化其他的bean
onRefresh();
// Check for listener beans and register them.
// 在所有注册的bean中查找listener bean,注册到消息广播器中
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 初始化剩下的单实例(非懒加载的)
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
// 为防止bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件bean
destroyBeans();
// Reset 'active' flag.
// 重置active标志
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
二、解析prepareRefresh()
该方法主要做一些容器刷新前的准备工作,主要分五部分
1、设置容器的启动时间
2、设置关闭状态为false
3、设置活跃状态为true
4、获取Environment对象,并加载当前系统的属性值到Environment对象中
5、准备监听器和事件的集合对象,默认为空的集合
protected void prepareRefresh() {
// Switch to active.
// 设置容器启动的时间
this.startupDate = System.currentTimeMillis();
// 容器的关闭标志位
this.closed.set(false);
// 容器的激活标志位
this.active.set(true);
// 记录日志
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// Initialize any placeholder property sources in the context environment.
// 留给子类覆盖,初始化属性资源
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
// 创建并获取环境对象,验证需要的属性文件是否都已经放入环境中
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
// 判断刷新前的应用程序监听器集合是否为空,如果为空,则将监听器添加到此集合中
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
// 如果不等于空,则清空集合元素对象
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
// 创建刷新前的监听事件集合
this.earlyApplicationEvents = new LinkedHashSet<>();
}
三、解析obtainFreshBeanFactory()
1.首先进入obtainFreshBeanFactory()方法,该方法主要是调用refreshBeanFactory()刷新内部的bean工厂,然后返回刷新后的bean工厂
/**
* 告诉子类刷新内部bean工厂
* Tell the subclass to refresh the internal bean factory.
* @return the fresh BeanFactory instance
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 初始化BeanFactory,并进行XML文件读取,并将得到的BeanFactory记录在当前实体的属性中
refreshBeanFactory();
// 返回当前实体的beanFactory属性
return getBeanFactory();
}
2.继续进入org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory方法
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果存在beanFactory,则销毁beanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建DefaultListableBeanFactory对象
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 为了序列化指定id,可以从id反序列化到beanFactory对象
beanFactory.setSerializationId(getId());
// 定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖
customizeBeanFactory(beanFactory);
// 初始化documentReader,并进行XML文件读取及解析,默认命名空间的解析,自定义标签的解析
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
此处可以通过继承的方式对customizeBeanFactory(beanFactory)进行扩展,或者修改是否允许bean覆盖和循环依赖的属性修改,核心方法是loadBeanDefinitions(beanFactory),即将配置文件中的bean解析加载至DefaultListableBeanFactory工厂中。
3.LoadBeanDefinitions有四种实现,如图
分别是基于xml,基于注解,基于Groovy和XmlWeb的,我们以xml为主,其余三种,大家可自行研读,原理相通。我们进入org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)方法,如下:
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
// 创建一个xml的beanDefinitionReader,并通过回调设置到beanFactory中
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
// 给reader对象设置环境对象,默认是StandardEnvironment
beanDefinitionReader.setEnvironment(this.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.
// 初始化beanDefinitionReader对象,此处设置配置文件是否要进行验证,子类可以重写
initBeanDefinitionReader(beanDefinitionReader);
// 开始完成beanDefinition的加载
loadBeanDefinitions(beanDefinitionReader);
}
这里 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);在创建beanDefinitionReader的时候,我们进入XmlBeanDefinitionReader的父类无参构造,这里做了两件事情
1、创建了资源加载器PathMatchingResourcePatternResolver,后续会用到
2.创建环境对象,默认StandardEnvironment,并且在创建中通过父类AbstractEnvironment的无参构造,调用子类的customizePropertySources方法加载系统环境变量,用户可通过继承的方式进行扩展
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
// Determine ResourceLoader to use.
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {
// 创建资源加载器,后面会用到
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
// Inherit Environment if possible
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
// 创建环境对象,默认StandardEnvironment
this.environment = new StandardEnvironment();
}
}
这里 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));在创建ResourceEntityResolver也通过父类的构造函数做了2件事情:
1.创建BeansDtdResolver对象,用以解析.dtd文件定义的标签
2.创建PluggableSchemaResolver对象,用以解析.xsd文件定义的标签,并在PluggableSchemaResolver的构造函数中默认了schema文件的映射路径:“META-INF/spring.schemas”
public DelegatingEntityResolver(@Nullable ClassLoader classLoader) {
this.dtdResolver = new BeansDtdResolver();
// 当完成这行代码的调用之后,大家神奇的发现一件事情,schemaResolver对象的schemaMappings属性被完成了赋值操作,但是你遍历完成所有代码后依然没有看到显式调用
// 其实此时的原理是非常简单的,我们在进行debug的时候,因为在程序运行期间需要显示当前类的所有信息,所以idea会帮助我们调用toString方法,只不过此过程我们识别不到而已
this.schemaResolver = new PluggableSchemaResolver(classLoader);
}
PluggableSchemaResolver中
public static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas";
最后通过loadBeanDefinitions(beanDefinitionReader)开启真正的beanDefinition的加载
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 以Resource的方式获得配置文件的资源位置
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
// 以String的形式获得配置文件的位置
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
4.doRegisterBeanDefinitions
经过各种loadBeanDefinitions的重载和重写的层层调用,最终到达org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions方法
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
// 前置处理,留给子类实现的扩展接口
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
// 后置处理,留给子类实现的扩展接口
postProcessXml(root);
this.delegate = parent;
}
并通过org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions对读取xml文件生成的Element对象进行解析
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
// 处理spring内部自定义的标签
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
// 处理非spring内部自定义的标签
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
spring内部自定义的标签只有import、alias、beans、bean四种,其余都属于非spring内部自定义的标签,需要通过delegate.parseCustomElement(ele)处理,我们将在下一章详述。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/130185.html