本文档基于Spring 5.1.4.RELEASE版本进行编写。
提前说一下,主要是为了给自己留一个印象,整篇下来更像是对源码的跟踪记录,想看整体概括描述的话可以看Spring 的骨骼架构。
其中bean的创建过程、动态代理和循环依赖的解决办法都没写,是因为文章的长度太长,写到另一个文章里面了,Spring 源码阅读-bean的创建、循环依赖的处理以及代理
在本文中,会使用加载配置文件的形式来完成容器的创建,展示的是
ClassPathXmlApplicationContext
的工作流程。
可以使用下面这段代码作为入口,来了解整个框架的启动过程。
在示例项目中使用的
ClassPathXmlApplicationContext
并不会被注册为bean,所以InitializingBean
的逻辑是不会工作的。
// 测试程序入口
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext(new String[] {"spring-config.xml"}, true, null);
HelloService helloService = (HelloService) ac.getBean("helloService");
helloService.sayHello();
1. Spring 框架的启动过程
1.1. 容器的创建
1.1.1. 构造函数
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
// ---------------------------------------------- 设置父级 ------------------------------------------------
// 在父级AbstractApplicationContext里面会创建一个ResourcePatternResolver类型的实例对象。
super(parent);
// ---------------------------------------- 解析传入的配置文件的地址 ------------------------------------------
// 解析传入的配置文件的地址,将结果存储在 AbstractRefreshableConfigApplicationContext 类的 configLocations 全局属性中
setConfigLocations(configLocations);
// ------------------------------------------- 容器的刷新 ------------------------------------------------
// 这个的逻辑比较长,为了文档目录看的好看,这里会在 容器的创建 同级添加一个标题 容器的刷新 来说明
if (refresh) {
refresh();
}
}
1.1.2. 对父级构造函数的调用
ClassPathXmlApplicationContext
的构造函数里有对父级的调用,整个调用过程是这样的
ClassPathXmlApplicationContext
->AbstractXmlApplicationContext
->AbstractRefreshableConfigApplicationContext
->AbstractRefreshableApplicationContext
->AbstractApplicationContext
其中只有AbstractApplicationContext
类内被调用的构造函数有点特殊。
public AbstractApplicationContext(@Nullable ApplicationContext parent) {
this();
setParent(parent);
}
public AbstractApplicationContext() {
// 创建一个ResourcePatternResolver类型的实例对象
// 这个东西是用来 把配置文件从地址字符串读取成Resource的,Resource是计算机文件的抽象存在。
this.resourcePatternResolver = getResourcePatternResolver();
}
// AbstractApplicationContext
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
1.1.3. 解析传入的配置文件的地址
这个步骤就是为了解析配置文件的地址,如果给定的地址中有占位符,则通过相应的环境属性值替换占位符。
// AbstractRefreshableConfigApplicationContext
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
// AbstractRefreshableConfigApplicationContext
protected String resolvePath(String path) {
// 通过换环境属性值替换占位符,这里不继续跟了,先看可以自己看看
return getEnvironment().resolveRequiredPlaceholders(path);
}
// AbstractApplicationContext
public ConfigurableEnvironment getEnvironment() {
// 这个环境可以在程序入口手动设置,不过需要使用 ConfigurableApplicationContext 作为父类引用指向 ClassPathXmlApplicationContext 对象实例
if (this.environment == null) {
// 这里面创建的是 StandardEnvironment 对象实例
this.environment = createEnvironment();
}
return this.environment;
}
上面代码中可以看出来配置文件的地址允许使用占位符,这里展示一下简单使用示例
new ClassPathXmlApplicationContext("spring-${type}.xml");
// 这个东西有使用前提,你必须想办法将在容器启动前把这个type放到环境变量
1.2 容器的刷新
容器刷新的主要目的是完成 bean 的创建和响应组件的创建,使得Spring Core的核心逻辑能够执行。
// AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// -------------------------------------------- 完成一些验证、准备操作 ---------------------------------------------
// Prepare this context for refreshing.
prepareRefresh();
// ------------------------------------------ 刷新当前IOC容器持有的内部容器 ----------------------------------------
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// ---------------------------------- 调用使用者在子类中自定义的内部容器的后处理 ------------------------------------------
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// 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();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
// --------------------------------------------- 处理IOC容器刷新异常时的行为 ----------------------------------------
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经创建的单例
destroyBeans();
// 重置 active 标识为 false,它用来标识当前上下文是否活跃的
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();
}
}
}
1.2.1. prepareRefresh(完成一些验证、准备操作)
结论先行,这个方法总体做了4件事情
1.设置一些标志属性
2.调用initPropertySources()
方法
3.对环境中必须的属性进行验证
4.为早期的ApplicationEvents
分配集合
// AbstractApplicationContext
protected void prepareRefresh() {
// -------------------------------- 设置一些标志属性 --------------------------------
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());
}
}
// -------------------------------- 调用initPropertySources()方法 -------------------------
// Initialize any placeholder property sources in the context environment (初始化在上下文环境中的所有占位符属性源)
// 这个是交由子类实现的,默认情况下什么都不做,可以自己搞一个容器的实现类试试重写这个方法。
initPropertySources();
// -------------------------------- 对环境中必须的属性进行验证 -------------------------
// Validate that all properties marked as required are resolvable (验证所有被标记为required的属性是存在的,如果有找不到的会抛出异常)
// getEnvironment() 在上面有说过,默认使用的是 StandardEnvironment 对象实例
// 可以在 initPropertySources() 的实现里面通过调用 getEnvironment().setRequiredProperties("xxx"); 添加required的属性
getEnvironment().validateRequiredProperties();
// ----------------------------- 为早期的ApplicationEvents分配集合 ---------------------
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
// 为早期的ApplicationEvents分配一个集合,在之后事件多播器创建完成后会将集合内堆积的事件进行发布。
// 就如同送信,你的信交给邮局,总得有邮递员去送出去,没有邮递员的时候,信会在邮局堆积,这里就是earlyApplicationEvents就类似临时邮局,多播器就相当于邮递员。(例子有点不恰当)
this.earlyApplicationEvents = new LinkedHashSet<>();
}
// AbstractPropertyResolver
public void validateRequiredProperties() {
MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
for (String key : this.requiredProperties) {
if (this.getProperty(key) == null) {
ex.addMissingRequiredProperty(key);
}
}
if (!ex.getMissingRequiredProperties().isEmpty()) { // 如果异常集合不为空,就抛出异常
throw ex;
}
}
1.2.2. obtainFreshBeanFactory(刷新当前IOC容器持有的内部容器)
当前IOC容器
是ApplicationContext容器
,内部IOC容器
指的是BeanFactory容器
,它也是IOC容器。
也就是说IOC容器有两类,分别是ApplicationContext容器
和BeanFactory容器
。
这个方法的主要逻辑是
创建一个新的内部IOC容器(DefaultListableBeanFactory
类型的),然后使用这个容器去解析配置文件,将解析到的BeanDefinition
存到IOC容器中等待下一步的操作(也就是用到是进行实例化)。
BeanDefinition
并不是我们使用的那些Bean的实例对象,它是我们交由IOC容器管理的bean的相关信息,每个bean都对应一个BeanDefinition
对象。
// AbstractApplicationContext
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 创建新的 BeanFactory 容器,并且对配置文件进行解析,完成对 BeanDefinition 的注册
refreshBeanFactory();
return getBeanFactory(); // 返回这个刚创建的 IOC容器
}
// AbstractRefreshableApplicationContext
protected final void refreshBeanFactory() throws BeansException {
// ---------------------------------------- 销毁已经存在的BeanFactory容器(内部IOC容器) ----------------------------------
// 每次刷新都会导致创建新的内部IOC容器,如果之前有,代表之前调用过上下文的刷新方法。
if (hasBeanFactory()) { // 如果已经有BeanFactory了 -> 销毁。
destroyBeans(); // 销毁存在的IOC容器内的Bean
closeBeanFactory(); // 清除存在的IOC容器(设置为null,等待垃圾回收处理)
}
try {
// ---------------------------------------- 构建新的的BeanFactory容器(内部IOC容器) ----------------------------------
DefaultListableBeanFactory beanFactory = createBeanFactory(); // 创建一个新的BeanFactory容器
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory); // 这个可以注意下,可以自定义内部IOC容器是否允许BeanDefinition覆盖 和 是否允许循环引用
// -------------------------------------- 从配置文件中解析BeanDefinition -------------------------------
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
1.2.2.1. createBeanFactory
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
protected BeanFactory getInternalParentBeanFactory() {
// getParent() 获取的就是父级的IOC容器,Spring MVC框架启动时应该会用到,这里用不到
return (getParent() instanceof ConfigurableApplicationContext ?
((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent());
}
这里主要就是想看
DefaultListableBeanFactory
的类结构关系,方便理解后续逻辑。
1.2.2.2. customizeBeanFactory
// AbstractRefreshableApplicationContext
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
// 设置 IOC容器是否允许BeanDefinition覆盖 和 是否允许循环引用
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
// 使用方式,要在上下文刷新之前设置。
ClassPathXmlApplicationContext ac = ...
ac.setAllowBeanDefinitionOverriding(false);
ac.setAllowCircularReferences(false);
ac.refresh();
1.2.2.3. loadBeanDefinitions
这个方法内有两个主要逻辑
1.组装一个XmlBeanDefinitionReader对象
2.使用组装的对象去解析配置文件中的内容,将解析到的BeanDefinition放入IOC容器内。
提醒:这个方法的调用链有点长,而且调用链中方法名重复性也很高
// AbstractXmlApplicationContext
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// ---------------------------------------- 组装XmlBeanDefinitionReader对象 ---------------------------------------------
// XmlBeanDefinitionReader对象的作用是解析配置文件(Xml),从中解析出来 BeanDefinition 放入IOC容器中
// Create a new XmlBeanDefinitionReader for the given BeanFactory. (为给定的 IOC容器 创建一个 XmlBeanDefinitionReader 实例对象)
// 这里需要注意下 XmlBeanDefinitionReader 的构造函数
// 它会把传入的IOC容器保存在自己的对象实例内,方便后续解析BeanDefinition时直接添加到IOC容器内。
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 这里的 this 是 ClassPathXmlApplicationContext对象实例,毕竟一开始创建的就是它,别记错。
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
// EntityResolver 对象在讲配置文件读成 Document 时有时用到
// 具体可见 XmlBeanDefinitionReader#doLoadBeanDefinitions 里面的逻辑,下面分析的步骤中有。
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 允许子类提供读取器的自定义初始化,然后继续实际加载bean定义。
initBeanDefinitionReader(beanDefinitionReader);
// ------------------------------------- 使用XmlBeanDefinitionReader对象解析配置文件 ----------------------------------------
loadBeanDefinitions(beanDefinitionReader);
}
这个方法内的有些方法调用都挺值的注意的,下面细看具体方法。
// AbstractBeanDefinitionReader
// 这个类是 XmlBeanDefinitionReader 的父类,XmlBeanDefinitionReader 的构造函数里调用了 super
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry; // 在 AbstractBeanDefinitionReader 中持有传入的这个IOC容器
// 按照 DefaultListableBeanFactory 的类结构图,这里必定会走到 else 代码块里。
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {
// 之前也说过 这个东西是用来 把配置文件从名称字符串读取成Resource的。
// 实际上,在现有逻辑内,这里创建的这个实例没什么用,在上层方法内会覆盖这个环境赋值
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
// 按照 DefaultListableBeanFactory 的类结构图,这里必定会走到 else 代码块里。
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
// 这里又创建了一个环境,之前在 AbstractApplicationContext 中也有
// 这个实例也会被上层方法覆盖,没什么用。
this.environment = new StandardEnvironment();
}
}
// AbstractXmlApplicationContext
protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
// 如果 validating 为true,代表会进行xml验证,如果关闭验证,此方法将打开名称空间感知,以便在这种情况下仍然正确处理模式名称空间。
reader.setValidating(this.validating);
}
// AbstractXmlApplicationContext
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
// 按照示例代码的逻辑,在这个方法才能获取到值。
// configLocations 存放的是 Spring 框架 配置文件的存放地址
String[] configLocations = getConfigLocations();
if (configLocations != null) {
// 通过 reader 来解析 xml 配置文件,下面继续分析这个方法
reader.loadBeanDefinitions(configLocations);
}
}
// ClassPathXmlApplicationContext
protected Resource[] getConfigResources() {
// 按照示例代码的逻辑,这里没有值
return this.configResources;
}
// AbstractRefreshableConfigApplicationContext
protected String[] getConfigLocations() {
// 在之前 ClassPathXmlApplicationContext 的构造函数中通过调用 setConfigLocations 方法已经设置过值了。
// getDefaultConfigLocations() 默认情况下也是返回 null
return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
}
上面的代码已经由
AbstractRefreshableApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory)
走到了
AbstractXmlApplicationContext#AbstractXmlApplicationContext(XmlBeanDefinitionReader)
里,但逻辑还没有完成。
现在要进入到
AbstractBeanDefinitionReader#loadBeanDefinitions(String[])
里看看是如何解析Xml文件的。
// AbstractBeanDefinitionReader
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int count = 0;
for (String location : locations) { // 迭代处理传入的多个配置文件的地址,示例代码实际只穿了1个
count += loadBeanDefinitions(location);
}
return count;
}
// AbstractBeanDefinitionReader
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
// AbstractBeanDefinitionReader
public int loadBeanDefinitions(String location, @Nullable Set actualResources) throws BeanDefinitionStoreException {
// 这里尝试获取的 ResourceLoader 就是 AbstractXmlApplicationContextloadBeanDefinitions(DefaultListableBeanFactory) 里设置的值
// 实际上就是程序入口创建的 ClassPathXmlApplicationContext 对象实例。
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
// 根据 ClassPathXmlApplicationContext 的类文件结构图,可以确定这里会进入 if 代码块
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
// 将 配置文件地址 解析成 Resource 对象
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
return count;
}
}
// AbstractApplicationContext
public Resource[] getResources(String locationPattern) throws IOException {
/*
* resourcePatternResolver 之前就说过,是用来把配置文件从地址字符串读取成Resource的,Resource是计算机文件的抽象存在。
*
* getResources(locationPattern) 太细节了,考虑到篇幅长度这里就不跟了,简述一下跟踪步骤(如果使用的是示例项目的话)
* PathMatchingResourcePatternResolver#getResources(String) 会进入 else 代码块里 else 代码块里
* DefaultResourceLoader#getResource(String) 会进入最下面的 catch 代码块里
* DefaultResourceLoader#getResourceByPath(String) 返回一个 ClassPathContextResource 类型的对象实例
*/
return this.resourcePatternResolver.getResources(locationPattern);
}
// AbstractBeanDefinitionReader
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
for (Resource resource : resources) {
count += loadBeanDefinitions(resource);
}
return count;
}
// XmlBeanDefinitionReader
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
// XmlBeanDefinitionReader
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
// ---------------------------------- 将要解析的Resource放到线程本地中 --------------------------------
Set currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources); // 因为对Set的操作是引用操作,这里直接存就行
}
// ------------------------------------ 检测配置文件的循环依赖 -----------------------------------------
if (!currentResources.add(encodedResource)) { // HashSet#add(Object)返回值表示的是:之前集合中是否存在相同元素
// 这里抛出 配置文件循环加载 的异常提示,在 xml 配置中代表
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
// --------------------------------------- 对I/O的操作 --------------------------------------------
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// ----------------------------------- 解析配置文件 --------------------------------------------
// 返回值代表这一次调用注册了多少个 BeanDefinition
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
// 从线程本地存储的集合中删除当前 解析的Resource, 代表某个配置文件已经解析并且注册完成。
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove(); // 代表所有的配置文件全部处理完成
}
}
}
到这里,各种各样的
loadBeanDefinitions
方法调用就到头了,它们都是讲数据类型转来转去传来传去的,没有真正的进行解析和注册工作。
在doLoadBeanDefinitions
方法中就要开始真正的解析配置文件并注册BeanDefinition
了。
// XmlBeanDefinitionReader
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 把文件读成 Document 对象,其中有对之前传入的 EntityResolver 对象的使用
Document doc = doLoadDocument(inputSource, resource);
// 注册解析到的 BeanDefinition 到 IOC 容器中,返回值代表这一次调用注册了多少个 BeanDefinition
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
// ... 省略了一大批 catch 代码块
}
// XmlBeanDefinitionReader
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 这里返回的是 DefaultBeanDefinitionDocumentReader 类的实例对象。
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 从IOC容器中获取到之前注册的 BeanDefinition 的数量
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 计算出这次注册了多少个 BeanDefinition
return getRegistry().getBeanDefinitionCount() - countBefore;
}
// XmlBeanDefinitionReader
public XmlReaderContext createReaderContext(Resource resource) {
// 传入的这个 this 很关键
// getNamespaceHandlerResolver() 不做跟踪,返回的是 DefaultNamespaceHandlerResolver 类的实例对象
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
// DefaultBeanDefinitionDocumentReader
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
// DefaultBeanDefinitionDocumentReader
protected void doRegisterBeanDefinitions(Element root) {
// ... 省略了解析配置文件的代码
preProcessXml(root); // 一个空Hook
parseBeanDefinitions(root, this.delegate);
postProcessXml(root); // 一个空Hook
// ...
}
// DefaultBeanDefinitionDocumentReader
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 如果根节点的命名空间是 http://www.springframework.org/schema/beans,那么会进入 if 代码块
// 也就是对 主命名空间/默认命名空间 的确认,如果不了解什么是命名空间的可以看 https://www.w3school.com.cn/tags/tag_prop_xmlns.asp
if (delegate.isDefaultNamespace(root)) {
// ... 省略了部分嵌套逻辑
if (delegate.isDefaultNamespace(ele)) { // 如果当前节点使用的是默认命名空间
// 标签使用的就是默认命名空间
parseDefaultElement(ele, delegate);
}
else {
// 、 这些它们使用的是各自的命名空间,分别是context和aop
// 这种的就会进入这里,关于这些的之后有空再具体跟,现阶段Spring的基础流程才是目的。
delegate.parseCustomElement(ele);
}
// ... 省略了部分嵌套逻辑
}
else {
// 根节点主命名空间是其它的情况,这里不考虑会进入这个方法,如果你自定义了主命名空间可以看看。
delegate.parseCustomElement(root);
}
}
// DefaultBeanDefinitionDocumentReader
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // 处理 标签的
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // 处理 标签的
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // 处理 标签的
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // 处理 标签的
// recurse
doRegisterBeanDefinitions(ele);
}
}
// DefaultBeanDefinitionDocumentReader
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// ---------------------------------------- 解析配置文件 ----------------------------------------
// 把 标签 解析成 BeanDefinitionHolder 对象实例,BeanDefinitionHolder 内部持有 BeanDefinition。
// 想具体了解就看 DefaultBeanDefinitionDocumentReader#parseBeanDefinitionElement(Element, BeanDefinition)
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 使用装饰者模式,对BeanDefinition进行装饰,实际上是解析自定义的元素,主要是两个操作
// 1.Decorate based on custom attributes first. (首先基于自定义的标签属性进行装饰)
// 2.Decorate based on custom nested elements. (然后基于自定义的子标签进行装饰)
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// --------------------------------- 注册BeanDefinition ------------------------------
// 第一个参数是持有目标 BeanDefinition 的 BeanDefinitionHolder
// 第二个参数是 IOC容器,这个之前在 XmlBeanDefinitionReader#createReaderContext(Resource) 传进来的,上面有
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// ------------------------------------ 发送BeanDefinition注册完成的事件 ----------------------
// 发送注册事件,也是 XmlBeanDefinitionReader#createReaderContext(Resource) 传进来的。
// 默认情况下这个事件什么都不做,可以通过手动在 XmlBeanDefinitionReader 中配置。
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
// BeanDefinitionReaderUtils
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// -------------------------- 注册BeanDefinition ---------------------------------
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 不再深入,想看可以去 DefaultListableBeanFactory#registerBeanDefinition
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// ------------------------------- 注册别名 ------------------------------------
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
1.2.3. prepareBeanFactory
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
// BeanExpressionResolver 这个和 Spring表达式语言SpEL 有关
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 添加 BeanPostProcessor
// ------------------------------------- 设置忽略注入的接口 -------------------------------------
// 这些会在DependencyCheck的处理逻辑中使用到
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 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)); // 添加 BeanPostProcessor
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (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()));
}
// ----------------------------------- 把环境相关的一些内容注册为单例 --------------------------------
// 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());
}
}
1.2.4. postProcessBeanFactory(调用使用者在子类中自定义的内部容器的后处理)
在执行这一步时,所有的
BeanDefinition
已经被加载完成,但还没有Bean
被实例化。
这一步就是允许在ApplicationContext
的子类中进行对内部IOC容器
的后处理,允许使用者在BeanDefinition
加载完成之后,在Bean
实例化之前对内部IOC容器做一些自定义的修改行为。
默认情况下,是一个空的实现,可以在子类内重写这个方法。
下面用一个示例展示 postProcessBeanFactory
的使用方式。
// 配置文件
现在我们要通过重写postProcessBeanFactory
方法,在它的过程内,变更配置文件里面设置的content
的值。
// 程序入口
public static void main(String[] args) {
ApplicationContext ac = new MyClassPathXmlApplicationContext(new String[]{"spring-config.xml"}, true, null);
}
class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
public MyClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(configLocations, refresh, parent);
}
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 这里已经获取到了 内部IOC容器,很多行为都是可以展开的。
BeanDefinition helloService = beanFactory.getBeanDefinition("helloService");
helloService.getPropertyValues().addPropertyValue("content", "world");
}
}
1.2.5. invokeBeanFactoryPostProcessors
对多种形式产生的
BeanFactoryPostProcessor
进行postProcessBeanFactory
方法的调用。
代码内涉及两类BeanFactoryPostProcessor
:
一类是实现了BeanFactoryPostProcessor
接口的
一类是实现了BeanDefinitionRegistryPostProcessor
接口的
BeanDefinitionRegistryPostProcessor
接口继承自BeanFactoryPostProcessor
接口
当使用者尝试自定义一个BeanDefinitionRegistryPostProcessor
接口的实现类时需要重写两个方法
1.postProcessBeanFactory(ConfigurableListableBeanFactory)
2.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)
建议只用来进行 BeanDefinition 的注册管理工作。
这里的这个postProcessBeanFactory方法
和AbstractApplicationContext#refresh()
里直接调用的postProcessBeanFactory方法
作用差不多,
只不过是使用方式和调用时机有些不同。
// AbstractApplicationContext
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
// AbstractApplicationContext
public List getBeanFactoryPostProcessors() {
// 可以通过 ConfigurableApplicationContext#addBeanFactoryPostProcessor 方法来添加内部IOC容器的后处理器,下面有展示
// 默认情况下这里是没有值的,Spring Boot框架中这里会传递一些值。
return this.beanFactoryPostProcessors;
}
// PostProcessorRegistrationDelegate
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set processedBeans = new HashSet<>(); // 存放的是 受内部IOC容器管理的 且 已被实例化过后的 BeanDefinitionRegistryPostProcessor
// 之前的逻辑里面可以知道内部容器是 DefaultListableBeanFactory 实现,通过它的类结构图可以看出来会进入下面这个 if 代码块
// IOC 容器继承自 BeanDefinitionRegistry 代表了什么? 代表了它内部可以管理 BeanDefinition 的注册等行为。
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 注意一下这两个集合的泛型类型。
List regularPostProcessors = new ArrayList<>(); // 存储常规的BeanFactory后处理器(也就是实现了BeanFactoryPostProcessor接口的)
List registryProcessors = new ArrayList<>(); // 存储所有 BeanDefinitionRegistryPostProcessor (被/不被容器管理的都在里面)
// ------------------------------------------------------- 处理没有被内部IOC容器管理的 BeanFactoryPostProcessor -------------------------------------------
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// ------------------------------------------------------- 处理内部IOC容器管理的 BeanDefinitionRegistryPostProcessor -------------------------------------------
// 在处理之前,它们都还是 BeanDefinition
/*
* 下面会出现3段极其相似的代码,目的是对 实现了PriorityOrdered 和 实现了Ordered 的 BeanDefinitionRegistryPostProcessor
* 进行区别对待,各自进行各自的排序。
*/
List currentRegistryProcessors = new ArrayList<>(); // 存储受IOC容器管理的 BeanDefinitionRegistryPostProcessor
/*
* 第一段相似代码
*
* 从内部IOC容器中找到实现了 PriorityOrdered 的 BeanDefinitionRegistryPostProcessor,
* 然后调用 beanFactory.getBean 把它们进行实例化(这时候它们就从BeanDefinition变成Bean了)
*
* 关于调用 beanFactory.getBean 可以是 BeanDefinition变成Bean 的逻辑之后再说。
*/
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); // 批量调用 postProcessBeanDefinitionRegistry 方法
currentRegistryProcessors.clear(); // 简单清除
// ---- 从内部IOC容器中找到实现了 Ordered 且 没有被上面处理过 的 BeanDefinitionRegistryPostProcessor 进行一样的处理过程
// 第二段相似代码
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);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// ---- 从内部IOC容器中找到其它没有被上面处理过 的 BeanDefinitionRegistryPostProcessor 进行一样的处理过程
// 第三段相似代码
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);
currentRegistryProcessors.clear();
}
// --------------------------------- 调用到目前为止处理的所有BeanFactoryPostProcessor的postProcessBeanFactory方法 -------------------------------
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// ------------------------------------------------------- 处理内部IOC容器管理的 BeanFactoryPostProcessor -------------------------------------------
// 在处理之前,它们都还是 BeanDefinition
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
List priorityOrderedPostProcessors = new ArrayList<>(); // 存储实现了 PriorityOrdered 的 BeanFactoryPostProcessor
List orderedPostProcessorNames = new ArrayList<>(); // 存储实现了 Ordered 的 BeanFactoryPostProcessor
List nonOrderedPostProcessorNames = new ArrayList<>(); // 存储没有实现排序的 BeanFactoryPostProcessor
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) { // 代表这个 BeanFactoryPostProcessor 已经被上面那段逻辑处理过了
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)); // 获取到实例化后的Bean
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 对实现了 PriorityOrdered 的 BeanFactoryPostProcessor 进行一些操作
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 对实现了 Ordered 的 BeanFactoryPostProcessor 进行一些操作
List orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); // 获取到实例化后的Bean
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// 对没有实现排序的 BeanFactoryPostProcessor 进行一些操作
List nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); // 获取到实例化后的Bean
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values... (清除已经缓存的合并的 BeanDefinition,因为 post-processors 可能修改了原始元数据(例如替换值中的占位符))
beanFactory.clearMetadataCache();
}
1.2.5.1. BeanFactoryPostProcessor接口的使用示例
// 首先是创建两个实现类
class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
下面展示两种形式的使用方式,实际上有多种方式能使用。
1.不受内部IOC容器管理
2.受内部IOC容器管理
// 第一种使用方式(不受内部IOC容器管理)
public class ApplicationContextTest {
public static void main(String[] args) {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"spring-config.xml"}, false, null);
ac.addBeanFactoryPostProcessor(new MyBeanDefinitionRegistryPostProcessor());
ac.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
ac.refresh();
}
}
// 第二种使用方式(受内部IOC容器管理)
// spring-config.xml 配置文件
public class ApplicationContextTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"spring-config.xml"}, true, null);
}
}
1.2.6. registerBeanPostProcessors
主要工作内容:
1.从内部IOC容器中找到实现了BeanPostProcessor
接口的BeanDefinition
。
2.全部进行Bean实例化,然后按照顺序添加到内部IOC容器的beanPostProcessors
集合中。
3.额外添加了BeanPostProcessorChecker
和ApplicationListenerDetectord
后处理器。
// todo: BeanPostProcessorChecker和ApplicationListenerDetector 要不要具体演示?
// AbstractApplicationContext
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
// PostProcessorRegistrationDelegate
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
/* 如果你使用的是示例项目, 调试的时候会看到这里有3个值
* 1.org.springframework.context.annotation.internalAutowiredAnnotationProcessor 来源于对标签的解析,见ContextNamespaceHandler
* 2.org.springframework.context.annotation.internalCommonAnnotationProcessor 来源于对标签的解析,见ContextNamespaceHandler
* 3.org.springframework.aop.config.internalAutoProxyCreator 来源于对系列标签的解析,见AopNamespaceHandler
* 它们都是 BeanDefinition 状态,它们也是在解析配置文件时被添加到容器内的
*/
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// BeanPostProcessorChecker的作用是:当一个bean不适合被所有BeanPostProcessor处理时,它会记录一条信息
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// ----------------------------------------------------- 处理内部IOC容器管理的 BeanPostProcessor -------------------------------------------------
// 在处理之前,它们都还是 BeanDefinition
// 也是对实现PriorityOrdered、实现Ordered、不实现排序的进行分开处理
List priorityOrderedPostProcessors = new ArrayList<>();
List internalPostProcessors = new ArrayList<>(); // 存放的是一些Spring框架内部的 BeanPostProcessor
List orderedPostProcessorNames = new ArrayList<>();
List nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); // 获取到实例化后的Bean
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// ------------------------- 处理实现了PriorityOrdered的BeanPostProcessors -------------------------------
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); // 把实例化的BeanPostProcessor放入内部IOC容器的beanPostProcessors集合中,下面的也都一样
// --------------------------- 处理实现了Ordered的BeanPostProcessors -------------------------------
List orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); // 获取到实例化后的Bean
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// --------------------------- 处理剩下的的BeanPostProcessors -------------------------------
List nonOrderedPostProcessors = new ArrayList<>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); // 获取到实例化后的Bean
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// --------------------------- 重新注册所有框架内部的BeanPostProcessor -----------------------------
// 重复注册只是改变BeanPostProcessor在链中的位置,不会造成重复出现的。
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).
// (把用于检测内部Bean的后处理器重新注册为ApplicationListeners,将其移动到后处理器链的末端(用于获取代理等操作))。
// ApplicationListenerDetector 用于检测那些实现了 ApplicationListener 接口的单例 bean,并且将它们放到 ApplicationContext 容器的监听器列表内。
// 如果有事件多播器,也同时放到多播器里面。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
1.2.7. initMessageSource
这一步的逻辑很简单,主要是对
MessageSource
的处理。
MessageSource
用于解析消息的策略接口,支持此类消息的参数化和国际化,可以配合Spring MVC中的LocaleResolver
使用。
public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 如果内部IOC容器中,不管任何形式存在这个东西,就会进入到 if 代码块
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class); // 获取到实例化后的Bean
// 设置上下级关系
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());
}
}
// ... 日志输出
}
else {
// Use empty MessageSource to be able to accept getMessage calls.
DelegatingMessageSource dms = new DelegatingMessageSource(); // 这实际上是个空壳,只是为了能够完成getMessage方法调用而提供的
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
// ... 日志输出
}
}
它的这部分处理代码很简单,没什么好说的,下面展示一下使用,示例项目中有提供代码。
// 这是启动类的代码
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"spring-config.xml"}, true, null);
TestService testService = ac.getBean("testService", TestService.class);
testService.test();
}
// 这是使用的代码
@Service
public class TestService {
@Autowired
private MessageSource messageSource;
public void test() {
System.out.println(messageSource.getMessage("message.key.hello", null, Locale.CHINESE));
System.out.println(messageSource.getMessage("message.key.hello", null, Locale.ENGLISH));
System.out.println("invoke test");
}
}
// 这是配置文件内的代码
在 resources/i18n/messages_en.properties 里面有这段代码
message.key.hello=hello
在 resources/i18n/messages_zh.properties 里面有这段代码
message.key.hello=你好
1.2.8. initApplicationEventMulticaster(初始化事件多播器)
这一步的逻辑跟很
initMessageSource
一样简单,主要是对ApplicationEventMulticaster
的处理。
ApplicationEventMulticaster
用于向ApplicationListener对象发布事件。
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
// ... 日志输出
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
// ... 日志输出
}
}
1.2.9. onRefresh
这是个Hook方法,就像
postProcessBeanFactory
方法一样,需要ApplicationContext
的子容器来自行实现。
在
onRefresh()
方法调用之前,Spring主要完成了
内部IOC容器的创建和对配置文件的解析、
BeanFactoryPostProcessor
的处理、
BeanPostProcessor
的处理、
MessageSource
的实例化、
ApplicationEventMulticaster
的实例化
在
onRefresh()
方法调用之后
注册监听器,发布早期事件
对non-lazy-init的bean进行初始化
收尾工作
在Spring Boot框架内,如果是默认的项目配置,那么会创建一个
AnnotationConfigServletWebServerApplicationContext
类型的IOC容器,在它的父类ServletWebServerApplicationContext
中有对onRefresh()
方法的重写。
通过查看代码可以看到,内部是对Servlet容器的创建,见ServletWebServerFactory#getWebServer
。
目前Spring Boot支持三种Servlet容器:1.Tomcat 2.Jetty 3.Undertow
1.2.10 registerListeners
主要做了两件事
1.注册所有受/不受内部IOC容器管理的ApplicationListener
。
2.通过多播器将earlyApplicationEvents
集合中存储的事件全部发布出去。
多播器的初始化见initApplicationEventMulticaster()
。
protected void registerListeners() {
// ---------------------------------------- 处理不受内部IOC容器管理的 ApplicationListener --------------------------------------------
// getApplicationListeners() 获取到是不受内部IOC容器管理的ApplicationListener集合,可以通过手动配置
for (ApplicationListener> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener); // 将ApplicationListener全部添加到事件多播器中。
}
// ----------------------------------------- 处理受内部IOC容器管理的 ApplicationListener --------------------------------------------
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); // 添加到事件多播器中
}
// --------------------------------------------- 发布之前堆积的 ApplicationEvent ---------------------------------------------------
// 在之前`prepareRefresh`方法中创建了earlyApplicationEvents集合,由于之前IOC容器中没有多播器,所以之前发布的事件都会存放在这个集合中
// 现在我们有了多播器(在initApplicationEventMulticaster()方法中创建了一个),只需要将堆积的事件通过多播器发布出去就行了。
Set earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
这里展示一下如何注册不受内部IOC容器管理的
ApplicationListener
,并让它们起作用。
// 这里不能使用 ApplicationContext 作为父类引用,使用 ClassPathXmlApplicationContext 或者 ConfigurableApplicationContext 这些都行。
public static void main(String[] args) {
// 要把构造函数内的 refresh 设置为 false,然后手动刷新。
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"spring-config.xml"}, false, null);
ac.addApplicationListener(event -> {});
ac.refresh(); // 手动刷新
}
1.2.11. finishBeanFactoryInitialization
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// ---------------------------------------------- 为当前IOC容器初始化一个 ConversionService ------------------------------------
// 初始化一个 ConversionService 并且设置给内部IOC容器 (前提是有的话)
// ConversionService 是一个用于类型转换的服务接口。 调用 convert(Object,Class) 以使用此系统执行线程安全类型转换。
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));
}
// ---------------------------------------------- 处理IOC容器中的嵌入式值解析器 ---------------------------------------------------
// 如果当前的IOC容器中没有嵌入式值解析器就添加一个默认的StringValueResolver
// 这个默认的嵌入式值解析器会试图从当前环境根据传入的key解析出来一个值,
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// ---------------------------------------------- 处理 LoadTimeWeaverAware ------------------------------------------------------
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. (尽早初始化LoadTimeWeaverAware,以便尽早注册它们的转换器。)
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName); // 获取到实例化后的Bean
}
// ---------------------------------------------- 对内部IOC容器的一些属性设置 -----------------------------------------------------
// Stop using the temporary ClassLoader for type matching. (停止使用临时类加载器进行类型匹配。)
beanFactory.setTempClassLoader(null);
// 冻结BeanDefinition的元数据,不再期待进一步的处理
beanFactory.freezeConfiguration();
// 实例化剩下的 non-lazy-init 的 bean
beanFactory.preInstantiateSingletons();
}
// DefaultListableBeanFactory
public void preInstantiateSingletons() throws BeansException {
// ... 日志打印
// 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 beanNames = new ArrayList<>(this.beanDefinitionNames);
// ------------------------------------------------- 初始化所有不是懒加载的bean ----------------------------------------------------
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { // 如果不是抽象的,是单例的,不是懒加载的
if (isFactoryBean(beanName)) {
// ------------------------------------- 对FactoryBean的处理 -----------------------------------------
// 普通的Bean的初始化行为会交由容器完成,是使用者无法控制的。
// FactoryBean的初始化行为则是交由类本身完成,是使用者可以自定义的。
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); // IOC容器对实现了FactoryBean接口的类会区别对待,方式就是在名字前加个&符号
if (bean instanceof FactoryBean) {
final FactoryBean> factory = (FactoryBean>) bean;
/*
* 首先判断是否实现了 SmartFactoryBean,如果实现了那就再判断 FactoryBean 是否是迫切加载的。
* SmartFactoryBean 是 FactoryBean 的子接口,内部额外提供了isPrototype和isEagerInit两个方法。
*/
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction)
((SmartFactoryBean>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean>) factory).isEagerInit());
}
// 如果 FactoryBean 明确指出是迫切加载的,则立刻执行Bean初始化操作
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// ------------------------------------- 对普通Bean的处理 -----------------------------------------
getBean(beanName);
}
}
}
// ------------------------------------ 调用实现了SmartInitializingSingleton接口的单例bean的afterSingletonsInstantiated方法 -------------------------------------
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction
1.2.11.1. 嵌入式值解析器的使用
// 这里不能使用 ApplicationContext 作为父类引用,使用 ClassPathXmlApplicationContext 或者 ConfigurableApplicationContext 这些都行。
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"spring-config.xml"}, true, null);
// 使用时要加上占位符
System.out.println(ac.getBeanFactory().resolveEmbeddedValue("${JAVA_HOME}"));
}
1.2.11.2. LoadTimeWeaver
LoadTimeWeaver 官方文档
Spring之LoadTimeWeaver——一个需求引发的思考
使用AspectJ LTW(Load Time Weaving)
代码织入(Weaving),指将切面代码插入到目标地方的过程,有3种方式(编译时织入-CTW、类加载时织入-LTW、运行时织入-RTW)。
在Spring中,也有提供了对LTW的支持,更多有关Spring LTW的内容点击此处查看。
CTW:在类的编译期,采用特殊的编译器,来织入切面
LTW:通过特殊的类加载器,在类加载到JVM时,替换字节码,来织入切面
RTW:采用CGLib或JDK动态代理进行切面的织入
框架名 CTW LTW RTW
AspectJ 支持 支持 不支持
Spring 不支持 支持 支持
1.2.11.3. FactoryBean 和 SmartFactoryBean 的使用示例
// FactoryBean 的使用示例
// 配置文件
// 自定义一个 FactoryBean
public class MyFactoryBean implements FactoryBean {
@Override
public MyFactoryBean getObject() throws Exception {
return new MyFactoryBean();
}
@Override
public Class> getObjectType() {
return MyFactoryBean.class;
}
@Override
public boolean isSingleton() { // 接口中是有默认值的,默认为true
return true;
}
}
SmartFactoryBean
是FactoryBean
的子接口,内部多了两个有默认值的方法(在JDK 1.8里),分别是
isPrototype()
默认值是false
,表示是否是多例;
isEagerInit()
默认值是false
,表示是否是迫切加载;
1.2.11.4. SmartInitializingSingleton的使用示例
@Service
public class TestService implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() {
}
}
1.2.11.5. AccessController
Java 安全模型介绍
// 在上文中可以看到这样一段代码
isEagerInit = AccessController
.doPrivileged(
(PrivilegedAction)((SmartFactoryBean>) factory)::isEagerInit,
getAccessControlContext()
);
// 这是最简形式
PrivilegedAction
如果已经阅读过上面那篇文章,就应该知道这样的一段代码表达的含义:让action
这一段受信任代码获得更大的权限。
1.2.12. finishRefresh
protected void finishRefresh() {
// ------------------------------------------------------ 清除 Resource 缓存 -------------------------------------------------------
// 什么时候缓存的? 上面说了有个步骤会调用 DefaultResourceLoader#getResource(String) 里最下面的catch代码块,就是那行代码,因为太细节所以上文没说。
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();
// ------------------------------------------------------ 初始化 LifecycleProcessor ----------------------------------------------
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// -------------------------------------------- 触发 LifecycleProcessor 的 onRefresh 方法 -----------------------------------------
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// ----------------------------------------------------- 发布 ContextRefreshedEvent 事件 ------------------------------------------
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
// ------------------------------------------------------ JMX的逻辑 ------------------------------------------------------------
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
1.2.12.1. initLifecycleProcessor
这一步的逻辑跟很
initMessageSource
一样简单,主要是对initLifecycleProcessor
的处理。
LifecycleProcessor
的主要作用是控制BeanFactory
中的所有实现Lifecycle
的单例bean的启动/停止。
protected void initLifecycleProcessor() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
this.lifecycleProcessor =
beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
// ... 日志打印
}
else {
DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
defaultProcessor.setBeanFactory(beanFactory);
this.lifecycleProcessor = defaultProcessor;
beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
// ... 日志打印
}
}
1.2.12.2. LiveBeansView
这个东西和JMX有关,是Spring在这一方面的实现,看不看都行。
在 Java 程序的运行过程中,对 JVM 和系统的监测一直是 Java 开发人员在开发过程所需要的。一直以来,Java 开发人员必须通过一些底层的 JVM API,比如 JVMPI 和 JVMTI 等,才能监测 Java 程序运行过程中的 JVM 和系统的一系列情况,这种方式一直以来被人所诟病,因为这需要大量的 C 程序和 JNI 调用,开发效率十分低下。于是出现了各种不同的专门做资源管理的程序包。为了解决这个问题,Sun 公司也在其 Java SE 5 版本中,正式提出了 Java 管理扩展(Java Management Extensions,JMX)用来管理检测 Java 程序(同时 JMX 也在 J2EE 1.4 中被发布)。
JMX 的提出,让 JDK 中开发自检测程序成为可能,也提供了大量轻量级的检测 JVM 和运行中对象 / 线程的方式,从而提高了 Java 语言自己的管理监测能力。
JMX 与系统管理
如果你已经看过上面的文档,你大概对JMX是什么以及怎么用有了一点了解,回头看Spring的
LiveBeansView
就知道他在干什么了
public class LiveBeansView implements LiveBeansViewMBean, ApplicationContextAware
// ...
public interface LiveBeansViewMBean {
String getSnapshotAsJson();
}