第一章 Spring之最熟悉的陌生人——IOC
第二章 Spring之假如让你来写IOC容器——加载资源篇
第三章 Spring之假如让你来写IOC容器——解析配置文件篇
第四章 Spring之假如让你来写IOC容器——XML配置文件篇
第五章 Spring之假如让你来写IOC容器——BeanFactory和FactoryBean
第六章 Spring之假如让你来写IOC容器——Scope和属性填充
第七章 Spring之假如让你来写IOC容器——属性填充特别篇:SpEL表达式
第八章 Spring之假如让你来写IOC容器——拓展篇
第九章 Spring之源码阅读——环境搭建篇
第十章 Spring之源码阅读——IOC篇
对于Spring一直都是既熟悉又陌生,说对它熟悉吧,平时用用没啥问题,但面试的时候被问的一脸懵逼,就很尴尬,都不好意思在简历上写着熟悉Spring了
所以决定花点时间研究研究Spring的源码。主要参考的书籍是:《Spring源码深度解析(第2版)》、《Spring揭秘》、《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》
前边跟着A君做了个简单的IOC容器,我们已经了解了一个简单的IOC容器的实现过程。不知道大家是否有所收获?接下来,就让我们把目光转到真正的IOC容器——spring中吧
要想了解Spring关于IOC,那必然需要从ApplicationContext接口入手,也许有些书籍、博客会从BeanFactory接口入手,这个也是一样的,BeanFactory提供了IOC容器的基本功能。这里从ApplicationContext开始是因为:一来前边《Spring之假如让你来写IOC容器》系列已经介绍过了IOC容器基本实现,二来ApplicationContext增加了许多高级特性:国际化,监听器等,读懂了更有助于我们了解Spring相关知识
纠结了半天,不知从何开始?按照之前看源码的经验来看,如果直接看源码,容易一叶障目,没过多久就看不下去了,所以这里决定先从ApplicationContext的接口设计入手,方便对ApplicationContext整体功能有个大概的认识,以下是ApplicationContext的UML图:
根据UML图可以看出,ApplicationContext大体实现了几个接口:BeanFactory、EnvironmentCapable、ApplicationEventPublisher、ResourceLoader、MessageSource。下边我们就来看下这几个接口的功能吧
这个接口想必是大家都很熟悉的一个接口、提供了IOC容器的基本实现,ListableBeanFactory、HierarchicalBeanFactory都是它的子接口,ListableBeanFactory上的注释直译是:可以枚举所有的bean实例的BeanFactory。它的方法大多数是统计Bean个数、根据条件去寻找相应的bean。HierarchicalBeanFactory则是为BeanFactory提供层次概念,简单来说就是有了父子工厂的概念。Spring很喜欢把功能拆的很细,然后用一个又一个的子接口去拓展其功能,BeanFactory就是个经典例子,像后边的ApplicationContext也是如此
EnvironmentCapable接口就比较单纯了,它只是用来获取环境对象的。直接说环境对象可能比较抽象。但是,如果说到Windows环境或者web环境,想必大家就明白了。假如需要获取一些系统变量,如果在Windows或者Linux下,则会去环境变量、JVM系统变量里边取,如果是web环境,也可以从ServletContext、ServletConfig里边获取
如果小伙伴们有看过之前的《Spring之假如让你来写IOC容器》系列,在《第八章 Spring之假如让你来写IOC容器——拓展篇》中定义的BeanFactoryEventPublisher,功能与之相似。简单来说,就是事件发布器,用来发布容器中的各种事件,让用户可以通过监听不同的容器事件来进行相应的拓展
ResourceLoader接口也是我们的老朋友了,早在《第二章 Spring之假如让你来写IOC容器——加载资源篇》就已经提到过了,是用来定位不同形式存放的资源,比如:classpath下的xml文件、fileSystem下的xml文件等
在现实生活中,存在着很多国家和地区,都用着不同的的语言。假如我们开发一个程序,走向了国际市场,程序的显示界面显然不能只支持中文显示,这样对不懂中文的人来说是个糟糕的体验。我们更希望在美国则显示英语,在中国则显示中文,这就是国际化需要解决的事情了。Spring也将这部分内容考虑进去了,MessageSource接口就是用来定义国际化相关内容的接口
经过上边的分析,我们已经了解ApplicationContext大概支持的功能:IOC容器、国际化、事件发布、资源加载。接下来,再来看下Spring是如何支持上述功能的吧
现在进入愉快的源码环节,我们以AbstractApplicationContext#refresh()方法作为入口,来一窥Spring的奥秘,源码如下:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//记录启动步骤
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
//准备刷新容器
// Prepare this context for refreshing.
prepareRefresh();
//准备BeanFactory(通常由子类实现)
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//初始化BeanFactory的一些配置
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
//空实现,由子类具体实现,方便子类在BeanFactory初始化完成后做一些操作
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
//记录开始执行post-process步骤
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
//执行BeanFactoryPostProcessor实现类
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
//注册BeanPostProcessor实现类
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
//记录执行post-process结束
beanPostProcess.end();
//初始化国际化支持
// Initialize message source for this context.
initMessageSource();
//初始化事件监听——多播器
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
//执行刷新内容,子类实现
// Initialize other special beans in specific context subclasses.
onRefresh();
//注册事件监听
// Check for listener beans and register them.
registerListeners();
//完成BeanFactory初始化,初始化所有非懒加载bean对象
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
//完成初始化
// Last step: publish corresponding event.
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.
destroyBeans();
// Reset 'active' flag.
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();
//记录结束
contextRefresh.end();
}
}
}
代码并不多,每一步要做什么,都有相应的注释。大致可以分为以下几步:
这种写法,有了解过设计模式相关知识的小伙伴应该一下子就看出来是模板模式。没了解过的小伙伴也不用太过担心,不必把它想的太过于复杂,设计模式一般都是基于代码复用、方便拓展的思路进行的,前辈们通过自己的经验归纳总结,就有了设计模式。我们就先来看下模板模式是何方神圣?
小时候,我们都有做过各式各样的脑筋急转弯,其中有个尤为经典:怎么把大象放进冰箱?当时难得我抓耳挠腮、坐卧不宁。其实答案很简单,只分成三步:
用代码描述就是:
public class Elephant {
public void put() {
//1、打开冰箱
openRefrigerator();
//2、放进大象
putElephant();
//3、关闭冰箱
closeRefrigerator();
}
protected void openRefrigerator() {
System.out.println("打开冰箱");
}
protected void putElephant() {
System.out.println("把大象放进冰箱");
}
protected void closeRefrigerator() {
System.out.println("关闭冰箱");
}
}
现在把问题换成:怎么把犀牛放进冰箱?还是原来的三个步骤,只是第二步有所变化:
代码描述就是:
public class Rhinoceros {
public void put() {
//1、打开冰箱
openRefrigerator();
//2、放进犀牛
putRhinoceros();
//3、关闭冰箱
closeRefrigerator();
}
protected void openRefrigerator() {
System.out.println("打开冰箱");
}
protected void putRhinoceros() {
System.out.println("把犀牛放进冰箱");
}
protected void closeRefrigerator() {
System.out.println("关闭冰箱");
}
}
这时候,重复的代码就出现了,而且重复率很高。后边如果问题又变成:怎么把老虎放进冰箱?难道还要再把第一步、第三步写一遍?显然,这对于有想法的程序员是难以忍受的。于是,就开始想办法提取公共的代码
优化方式也很简单,java是面向对象语言,天生具备多态的特性。只要让父类实现公共部分,子类做特性化实现就可以。代码就变成了:
public abstract class Animal {
public void put() {
//1、打开冰箱
openRefrigerator();
//2、放进动物
putAnimal();
//3、关闭冰箱
closeRefrigerator();
}
protected void openRefrigerator() {
System.out.println("打开冰箱");
}
protected abstract void putAnimal();
protected void closeRefrigerator() {
System.out.println("关闭冰箱");
}
}
上边的修改虽然让代码结构变复杂了,但是代码复用性却是提高了,具体要放什么,由子类去实现
也许扯得有点远,回到我们的Spring。再把这些思路代入到之前的AbstractApplicationContext#refresh()方法中,是不是就清楚了些?如果在Spring中看到空实现的方法,大概率就是留给子类拓展用的
了解完大致流程,接下来就是具体实现细节了。前边《Spring之假如让你来写IOC容器》系列已经介绍过了容器的实现细节,这里不再进入到去看每一步的实现细节,就看下每一步具体做了什么。下面内容可能代码会有点多,还望大家耐心点看完
之前已经看过了 ApplicationContext 实现了那些功能,接下来看下 ApplicationContext 有哪些实现(去除了注解和web的相关内容,只看XML实现)。如下:
Spring的设计思路大抵是先定义个只包含基础功能的接口,而后用一个个子接口去拓展其功能,再定义抽象类提取公共代码,最后才是真正的实现
前置操作并没有太多的逻辑,主要是设置一些状态以及系统属性及环境变量的初始化及验证。源码如下:
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
//关闭状态置为false
this.closed.set(false);
//激活状态置为true
this.active.set(true);
//初始化配置参数
// 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<>();
}
设置状态的部分没啥好说的,这段代码主要的部分是在初始化参数和验证参数上。接下来一起来看看initPropertySources() 和 getEnvironment().validateRequiredProperties() 具体做了啥
先来看 initPropertySources() 具体做了什么:
点开 initPropertySources 方法,我们惊奇的发现,竟然是空实现。联想之前的模板模式,再结合代码上的注释,可以推断出:这是留给子类实现的,各个子类按自己需求去重写。SpringMvc就重写了该方法,用以初始化ServletContext相关参数。有了参数之后,大部分情况下会对一些必要的参数进行校验,Spring也是如此,validateRequiredProperties就是对启动时必要的参数进行验证。跟着方法调用一路点下去,最终停在了AbstractPropertyResolver#validateRequiredProperties()上边,源码如下:
代码方面并没有什么出奇的地方,当requiredProperties属性存在空值时,就会被记录,最终一起抛出异常
校验完参数后,接下来就是准备容器的早期事件。什么叫做早期事件?刚看到的时候一脸懵逼。Spring的事件都是通过多播器(ApplicationEventMulticaster)进行的,而多播器(ApplicationEventMulticaster)是在方法AbstractApplicationContext#refresh()中执行完 initApplicationEventMulticaster()才初始化的,远远晚于AbstractApplicationContext#prepareRefresh()方法。那么早期意义又在哪里?确实事件都是在多播器(ApplicationEventMulticaster)初始化之后才执行的,之所以要单独弄个早期事件,可能是为了区分系统事件和用户自定义事件。由于系统事件不适合配置在xml或者注解上,故而有早期事件这么一说。SpringBoot里边可以看到大量使用,都配置在spring.factories中,
SpringBoot具体内容这里就先不谈,还不懂。先混个眼熟即可。配置如下:
在准备好容器的前置操作后,容器也进入了下一个步骤——准备BeanFactory,BeanFactory 应该是我们最为熟悉的一个接口,接下来一起来看下Spring是如何对其进行初始化的,源码如下:
AbstractApplicationContext#obtainFreshBeanFactory() 方法并没有多少代码,看不出个所以然来。接着跟进 refreshBeanFactory() 方法中,源码如下:
refreshBeanFactory() 竟然是个抽象方法,那只能找他的子类实现,其实现主要有两个:GenericApplicationContext、AbstractRefreshableApplicationContext 。两个类功能不太一样,GenericApplicationContext 主要提供编程式的实现,或许编程式太过于术语化了。简单的说就是:需要写代码,每一步需要做什么都通过写代码来实现功能。就像 GenericApplicationContext 类上的注释那样实现,如下:
GenericApplicationContext ctx = new GenericApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties"));
ctx.refresh();
MyBean myBean = (MyBean) ctx.getBean("myBean");
与编程式对应的自然就是声明式了,简单来说:就是通过配置就能实现功能,像XML、注解等。并不需要额外的写代码。而平时工作中,不论是SpringBoot也好,还是单纯的Spring。很少编程式方式进行开发,一般都是通过注解或XML的形式实现的。所以这次主要看下 AbstractRefreshableApplicationContext 的实现,源码如下:
这段代码的核心就集中在 customizeBeanFactory(beanFactory) 和 loadBeanDefinitions(beanFactory) 上。customizeBeanFactory(beanFactory) 虽然重要,但是其实现相当简单,只是设置了allowBeanDefinitionOverriding和allowCircularReferences属性而已,源码如下:
我们接着把目光转到 loadBeanDefinitions(beanFactory) 方法上,这个方法就是加载 bean 配置信息的地方。如果可以看懂之前的 《第三章 Spring之假如让你来写IOC容器——解析配置文件篇》 和 《第四章 Spring之假如让你来写IOC容器——XML配置文件篇》,相信这里也难不倒各位。这里就不继续往下跟了
创建完 BeanFactory 并加载完XML配置之后,接着就需要对BeanFactory添加一些配置。比如:Spel解析器、忽略Aware相关接口、注入默认Bean等。故此,代码虽然多,却没有什么难度的。源码如下:
/**
* Configure the factory's standard context characteristics,
* such as the context's ClassLoader and post-processors.
*
* @param beanFactory the BeanFactory to configure
*/
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
if (!shouldIgnoreSpel) {
//添加SPEL解析器
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
}
//添加类型转换器,由wrapper#init()触发
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
//添加ApplicationContextAwareProcessor事件,用以设置Aware相关属性
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
/**
* 忽略Aware相关接口,因为ApplicationContextAwareProcessor会去设置相关内容
*/
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);
//注册这些类,方便属性使用byType注入时可以使用
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
//如果未定义bean,则将相关组件注册进去
// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
}
}
ignoreDependencyInterface 是忽略某个类型接口,像EnvironmentAware、MessageSourceAware等接口,是Spring内部组件,不需要另行创建。如果对此有疑惑的小伙伴,点进ApplicationContextAwareProcessor类中,即可知道缘由,Spring为何要忽略这些接口。源码如下:
registerSingleton则是注册一个单例对象,如果容器中不存在Environment、ApplicationStartup相关bean对象,就用Spring默认的组件
这里还需要注意一下registerResolvableDependency方法,再说这个之前,需要提一嘴Spring依赖注入方式有三种:no(AUTOWIRE_NO)、byName(AUTOWIRE_BY_NAME)、byType(AUTOWIRE_BY_TYPE)。如果是no、byName,registerResolvableDependency并没有什么卵用,只有是byType时才起作用。说一千道一万,不如实验一下。定义Student类,如下:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
@Component
public class Student {
private String name;
@Autowired
private ResourceLoader resourceLoader;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ResourceLoader getResourceLoader() {
return resourceLoader;
}
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
xml配置如下:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="studentByDefault" class="com.hqd.test.bean.Student" autowire="default">
<property name="name" value="asdasd"/>
bean>
<bean id="studentByName" class="com.hqd.test.bean.Student" autowire="byName">
<property name="name" value="asdasd"/>
bean>
<bean id="studentByType" class="com.hqd.test.bean.Student" autowire="byType">
<property name="name" value="asdasd"/>
bean>
beans>
Student类中包含了ResourceLoader,而在xml配置中并没有注入。ResourceLoader类在Bean工厂初始化时,也就是执行prepareBeanFactory方法时会通过registerResolvableDependency方法注册到工厂中,如果成功注入进去,ResourceLoader自然也就有值了,测试代码如下:
@Test
public void resolvableDependency() {
ApplicationContext factory = new ClassPathXmlApplicationContext("dependency.xml");
Student studentByDefault = factory.getBean("studentByDefault", Student.class);
Student studentByName = factory.getBean("studentByName", Student.class);
Student studentByType = factory.getBean("studentByType", Student.class);
System.out.println("sssss");
}
打印结果如下:
可以看到只有用byType属性注入方式才有值,其他两个并没有,也就证实了前边的说法
BeanFactory已经初始化完成了,可以进行后续操作了。接着我们愉快的点进postProcessBeanFactory方法中,源码如下:
咦?怎么是个空实现?回想起之前提到过的模板模式,就马上释然了。想必也是留给子类去拓展用的。经典的用途就是springMVC添加了自己的BeanPostProcessor和ignoreDependencyInterface,不过这属于web的内容,这里就先不涉及了
BeanFactory准备完成了,该加的功能也都加了。接下来Spring就要开始考虑拓展了,毕竟业务是千变万化的,万一有个业务场景就是要在BeanFactory准备完成之后做操作,总不能让使用者去修改Spring源码吧。于是乎,就有了BeanFactoryPostProcessor接口用以拓展。知道了invokeBeanFactoryPostProcessors的作用,接着就来看下Spring是如何实现的吧。源码如下:
invokeBeanFactoryPostProcessors方法中,并未有相关的实现,而是委托给了PostProcessorRegistrationDelegate类,这在Spring中已经是司空见惯了。继续跟进PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(),源码如下:
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// WARNING: Although it may appear that the body of this method can be easily
// refactored to avoid the use of multiple loops and multiple lists, the use
// of multiple lists and multiple passes over the names of processors is
// intentional. We must ensure that we honor the contracts for PriorityOrdered
// and Ordered processors. Specifically, we must NOT cause processors to be
// instantiated (via getBean() invocations) or registered in the ApplicationContext
// in the wrong order.
//
// Before submitting a pull request (PR) to change this method, please review the
// list of all declined PRs involving changes to PostProcessorRegistrationDelegate
// to ensure that your proposal does not result in a breaking change:
// https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//先执行编码添加的BeanFactoryPostProcessor,只有通过编码添加beanFactoryPostProcessors才有值
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
/**
* BeanDefinitionRegistryPostProcessor直接执行
*/
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
} else {
/**
* 其他BeanFactoryPostProcessor加入regularPostProcessors列表
*/
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
//先找出实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
//再找出实现了Ordered接口的BeanDefinitionRegistryPostProcessor
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
//使用Ordered继续排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
//执行BeanDefinitionRegistryPostProcessor
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
//最后找出剩余的BeanDefinitionRegistryPostProcessor
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
}
//现在才开始执行BeanFactoryPostProcessor#postProcessBeanFactory方法
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
//执行通过编码添加的BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
} else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
//接着执行BeanFactoryPostProcessor,顺序与上边一致
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
} else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
} else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
这段代码看着挺长的,其实只做了一件事:执行顺序。因为BeanFactoryPostProcessor除了它自己,也存在子接口:BeanDefinitionRegistryPostProcessor。BeanFactoryPostProcessor本身可以通过编码或者配置文件的方式添加,Spring又存在PriorityOrdered和Ordered接口进行排序。这就难免涉及到了谁先谁后的问题
首先实现不同接口的BeanFactoryPostProcessor,执行顺序BeanDefinitionRegistryPostProcessor =》BeanFactoryPostProcessor。再来是实现同一个接口的,执行顺序:编码添加 =》实现了PriorityOrdered接口 =》实现了Ordered接口 =》其他。这就是上边那段代码的全部思路,虽然多,但是以这个思路去看,耐住性子,不会太难的
执行完BeanFactoryPostProcessor相关实现类,紧接着的就是注册BeanPostProcessor相关实现,注意这里只是注册,并没有执行。因为BeanPostProcessor是在创建bean的时候才去调用的,所以这里只是注册。源码如下:
这里和BeanFactoryPostProcessor一样,都委托给工具类去执行。继续跟进,源码如下:
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// WARNING: Although it may appear that the body of this method can be easily
// refactored to avoid the use of multiple loops and multiple lists, the use
// of multiple lists and multiple passes over the names of processors is
// intentional. We must ensure that we honor the contracts for PriorityOrdered
// and Ordered processors. Specifically, we must NOT cause processors to be
// instantiated (via getBean() invocations) or registered in the ApplicationContext
// in the wrong order.
//
// Before submitting a pull request (PR) to change this method, please review the
// list of all declined PRs involving changes to PostProcessorRegistrationDelegate
// to ensure that your proposal does not result in a breaking change:
// https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22
//获取所有BeanPostProcessor实现类
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
//匹配实现PriorityOrdered接口的
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {//匹配实现Ordered接口的
orderedPostProcessorNames.add(ppName);
} else {//其他
nonOrderedPostProcessorNames.add(ppName);
}
}
//先注册实现PriorityOrdered接口的
// First, register the BeanPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
//在注册实现Ordered接口的
// Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
//最后注册其他BeanPostProcessor
// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
BeanPostProcessor注册顺序和BeanFactoryPostProcessor大体一致:实现了PriorityOrdered接口 =》实现了Ordered接口 =》其他。相较于BeanFactoryPostProcessor,会发现少了个编码方式的处理,其实原因也简单,因为BeanFactoryPostProcessor需要执行,所以需要用处理编码方式添加进去的类,而BeanPostProcessor只是单纯的注册,用编码方式添加进去的类,已经在列表中了,根本不需要处理
在测试时候,发现一个有趣的事,这里一起分享给大家。首先,定义个Bean,并且实现BeanPostProcessor 接口。代码如下:
public class CarBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化钱");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化hou");
return bean;
}
}
xml配置如下:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="carBeanPostProcessor" class="com.hqd.test.bean.CarBeanPostProcessor"/>
beans>
测试代码如下:
@Test
public void beanPostProcessorTest() {
ApplicationContext factory = new ClassPathXmlApplicationContext("bean-post.xml");
CarBeanPostProcessor carBeanPostProcessor = factory.getBean(CarBeanPostProcessor.class);
System.out.println(carBeanPostProcessor);
}
这时候运行会打印CarBeanPostProcessor相关信息吗?
tips:答案就在上边的源码中
其实不会的,之前我也纳闷了好久。原因在于:BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class) 这行代码上,由于这时候还没有注册BeanPostProcessor,所以这时候getBean并不会执行CarBeanPostProcessor。而这时候Bean又已经注册到工厂缓存中去了,所以下次getBean时,会从缓存中获取,也不会执行BeanPostProcessor。故而不会打印CarBeanPostProcessor的相关信息
初始化国际化资源相对比较简单,如果用户没有创建MessageSource的话,则Spring就会使用默认MessageSource,也就是DelegatingMessageSource。源码如下:
protected void initMessageSource() {
//获取工厂
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
/**
* 判断工厂中是否已经存在messageSource
* 存在则为其设置父消息资源解析器
* 不存在则使用默认消息资源解析器
*/
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// Make MessageSource aware of parent MessageSource.
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// Only set parent context as parent MessageSource if no parent MessageSource
// registered already.
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]");
}
} else {
//创建默认messageSource,并注册到工厂中
// Use empty MessageSource to be able to accept getMessage calls.
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isTraceEnabled()) {
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
}
}
}
代码方面没什么出奇的地方,这里顺带聊下国际化相关的内容(水水字数)
java本身就自带国际化处理——ResourceBundle,Spring 也是在其基础上做了相应的封装。ResourceBundle工作原理也简单,定义不同的资源文件,根据当前地区读取对应的配置即可。做个简单的例子体验一下,现在定义两个配置文件:messages_en_US.properties,messages_zh_CN.properties。messages_en_US.properties配置如下:
test=test
info=At {1,time,short} On {1,date,long} {0} paid {2,number, currency}.
messages_zh_CN.properties配置如下:
test=测试
info={0},你好!你于{1}在工商银行存入{2}元。
测试代码如下:
@Test
public void messageSourceTest() {
Object[] params = {"John", new GregorianCalendar().getTime(), 1.0E3};
Locale zh = Locale.CHINA;
Locale us = Locale.US;
//根据本地地区信息获取
ResourceBundle messages = ResourceBundle.getBundle("test/messages", zh);
String testKey = "test";
String infoKey = "info";
String test = messages.getString(testKey);
String info = MessageFormat.format(messages.getString(infoKey), params);
System.out.println(String.format("中文:%s:%s %s:%s", testKey, test, infoKey, info));
//获取英文地区
messages = ResourceBundle.getBundle("test/messages", us);
test = messages.getString(testKey);
info = MessageFormat.format(messages.getString(infoKey), params);
System.out.println(String.format("英文:%s:%s %s:%s", testKey, test, infoKey, info));
// ApplicationContext ctx = new ClassPathXmlApplicationContext("message.xml");
// Object[] params1 = {"John", new GregorianCalendar().getTime()};
// String str1 = ctx.getMessage("test", params1, Locale.US);
// String str2 = ctx.getMessage("test", params1, Locale.CHINA);
// System.out.println(str1);
// System.out.println(str2);
}
结果也如所期望的一样,如下:
事件发布器的初始化去国际化并无二致,甚至比国际化更为简单(不涉及父级结构)。关于事件发布器在《第八章 Spring之假如让你来写IOC容器——拓展篇》也有相关的模拟,这里就不再废话了,直接看源码。源码如下:
这里需要注意一下,SimpleApplicationEventMulticaster发布器是支持异步的,只需要给他个线程池即可。源码如下:
可以看到,当taskExecutor不为空时,就会使用异步执行
初始化完多播器后,就可以注册事件了。注册的事件包含:早期事件、实现相关事件接口的Bean。这里只是注册,因为必须等到代码执行到对应事件时,才会触发对应的事件。源码如下:
protected void registerListeners() {
//注册早期事件
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
//添加实现相关接口的bean
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
//发布早期事件,并清空早期事件
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
这部分代码相信大伙儿都看得懂,先添加早期事件,再添加实现相关事件接口的Bean到多播器中,最后触发早期事件。也是在这里,我们心心念念的早期事件终于开始执行了。要知道早期事件可是在容器刷新前置操作——prepareRefresh方法中就添加了
经过前边一系列准备,容器已经准备的差不多了。接下来Spring需要加载Bean对象了。Bean对象可以分成:懒加载、非懒加载两种形式,这里只会初始化非懒加载且单例的Bean。源码如下:
/**
* Finish the initialization of this context's bean factory,
* initializing all remaining singleton beans.
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//设置类型转换器
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
//添加占位符解析器
// Register a default embedded value resolver if no BeanFactoryPostProcessor
// (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
//代理相关,暂不涉及
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
//冻结beanDefinition,不能在进行修改
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
//初始化bean
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
在初始化bean之前,Spring会先准备类型转换器、占位符解析器。在设置属性时,需要使用他们进行转换后赋值。接着就是冻结BeanDefinition,不允许再对BeanDefinition进行改了,最后进行单例bean对象的初始化。其他部分就不进行多少,主要来看下初始化bean部分,preInstantiateSingletons 方法源码如下:
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
//合并BeanDefinition,因为存在继承
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
//实现了SmartFactoryBean接口,是否需要提前加载
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
} else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
//是否需要提前加载
if (isEagerInit) {
getBean(beanName);
}
}
} else {
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
//执行所有实现了SmartInitializingSingleton接口
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
smartInitialize.end();
}
}
}
代码也没有太多出奇的地方,只是添加了SmartFactoryBean和SmartInitializingSingleton接口的支持。初始化bean的具体操作交给了BeanFactory
到了这里,容器初始化也就接近了尾声,容器也进行收尾工作了。源码如下:
1、首先Spring容器会清除Resource的相关缓存
2、初始化lifecycleProcessor,这个是生命周期的处理器。因为Spring存在着生命周期接口——Lifecycle。不过就算实现了Lifecycle接口,Spring也不会被调用,需要手动调用。只有实现了SmartLifecycle接口才会被getLifecycleProcessor().onRefresh()所执行
3、发布容器刷新事件,所有监听ContextRefreshedEvent的监听器都会被执行
前前后后折腾了好久,总算把Spring IOC部分整完了,对Spring理解总算上升了一点。当然以上纯属个人理解,如果有啥错误的地方欢迎的大家指出(✪ω✪)