一. 统一资源加载策略:
-
Spring 将资源的定义和资源的加载区分出来
- 资源描述接口:
Resource
- 资源加载规则接口:
ResourceLoader
用来根据定义的资源文件地址, 返回Resource
对象. 该接口只有 2个方法
Resource getResource(String location); // 核心方法, 返回Resource ClassLoader getClassLoader();
- 资源描述接口:
-
资源和加载接口提供了默认实现
-
org.springframework.core.io.AbstractResource
为Resource
接口的默认抽象实现
它实现了Resource
接口的大部分的公共实现. 实现的默认方法包括: 判断文件是否存在, 最后修改时间等 -
DefaultResourceLoader
类 为ResourceLoader
的默认实现, 每次只能返回单一的资源 -
PathMatchingResourcePatternResolver
是一个集大成者的ResourceLoader
. 它还实现了额外的接口ResourcePatternResolver
.
既有Resource getResource(String location)
方法,也有Resource[] getResources(String locationPattern)
方法。
-
二. 加载 BeanDefinition
先看一段 spring 使用的标准代码
// <1> 获取资源
ClassPathResource resource = new ClassPathResource("application1.xml");
// <2> 获取 BeanFactory
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// <3> 组合 BeanFactory 创建 BeanDefinitionReader, 该 Reader 为 Resource 的解析器
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
// <4> 装载 Resource
reader.loadBeanDefinitions(resource);
注释中初步给出 spring 容器的使用过程. 该过程可分三步理解:
- 资源定位: 比如如果用 beans.xml 配置 bean, 则首先要拿到 beans.xml 这个资源文件. 这一步是返回
Resource
的过程 - 装载:
使用BeanDefinitionReader
解析Resource
文件, 将文件内容转变成BeanDefinition
结构- 在 IoC 容器内部维护着一个
BeanDefinition Map
的数据结构 - 在配置文件中每一个
都对应着一个BeanDefinition
对象。
- 在 IoC 容器内部维护着一个
- 注册
将解析出的 BeanDefinition 对象通过BeanDefinitionRegistry
接口来实现注册, 将这些解析的 BeanDefinition 注入到一个HashMap
容器中
此时并没有创建 bean. 只是注册了 BeanDefinition
- 装载 BeanDefinition 在上面第<4>步
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); } // this.resourcesCurrentlyBeingLoaded 是一个 ThreadLocal
>, 记录当前线程注册过的 EncodedResource Set currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try (InputStream inputStream = encodedResource.getResource().getInputStream()) { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } // <核心流程>: 解析 Resource ,生成 BeanDefinition return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { // 当 currentResources 为空时, 证明该 ThreadLocal 已经不会被使用. 这会导致 ThreadLocalMap.Entry // 键值对内部的 ThreadLocal key 软引用在 gc 时被置空. 而 key 为 null 的 value 访问不到, 却又 gc 不了, 导致溢出 // 要及时把不再使用的 ThreadLocal 调用 remove 删除 this.resourcesCurrentlyBeingLoaded.remove(); } } } - 核心流程
doLoadBeanDefinitions()
// XmlBeanDefinitionReader.java protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { // <1> 解析 xml Resource, 返回 xml 的 Document 对象 Document doc = doLoadDocument(inputSource, resource); // <2> 从 Document 对象中解析出 BeanDefinition 并注册 int count = registerBeanDefinitions(doc, resource); if (logger.isDebugEnabled()) { logger.debug("Loaded " + count + " bean definitions from " + resource); } return count; } }
- <2> 步骤
registerBeanDefinitions(doc, resource)
返回注册的 BeanDefinition 个数
// AbstractBeanDefinitionReader.java private final BeanDefinitionRegistry registry; // XmlBeanDefinitionReader.java public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // <1> 创建 BeanDefinitionDocumentReader 对象 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); // <2> 获取已注册的 BeanDefinition 数量 int countBefore = getRegistry().getBeanDefinitionCount(); // <3> 创建 XmlReaderContext 对象 // <4> 注册 BeanDefinition documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); // 计算新注册的 BeanDefinition 数量 return getRegistry().getBeanDefinitionCount() - countBefore; }
-
BeanDefinition
是去用来描述一个 bean.
它的属性对应 xml 中配置的属性. 比如: 生成 bean 的工厂类, 生成 bean 的工厂方法, bean 的构造函数, bean 的 scope 等
- <2> 步骤
- 什么是
BeanDefinition
的注册
就是将
和
两种映射关系注册到BeanFactory
中- 步骤<1>, 注册 beanName 和 BeanDefinition 的方法是定义在 BeanFactory 内的.
BeanFactory
内部持有 beanName 和 BeanDefinition 映射的 ConcurrentHashMap. 添加映射时, 还要用同步块处理并行的情况
// DefaultListableBeanFactory.java // 是否允许同名 beanName 的 BeanDefinition 进行覆盖注册: true private boolean allowBeanDefinitionOverriding = true; /** 存储 beanName 和 BeanDefinition 映射的 HashMap */ private final Map
beanDefinitionMap = new ConcurrentHashMap<>(256); /** List of bean definition names, in registration order. */ private volatile List beanDefinitionNames = new ArrayList<>(256); /** List of names of manually registered singletons, in registration order. */ private volatile Set manualSingletonNames = new LinkedHashSet<>(16); @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { ... // 省略各种校验和判断是否可以覆盖同 beanName 和 BeanDefinition 的设置 // beanDefinitionMap 为全局变量,避免并发情况 // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { // 添加到 BeanDefinition 到 beanDefinitionMap 中。 this.beanDefinitionMap.put(beanName, beanDefinition); // 添加 beanName 到 beanDefinitionNames 中 List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; // 从 manualSingletonNames 移除 beanName if (this.manualSingletonNames.contains(beanName)) { Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } - 步骤 <2> 中的注册 beanName 和 regist name 映射, 也是注册到一个 ConcurrentHashMap 中
// SimpleAliasRegistry,java /** Map from alias to canonical name. */ private final Map
aliasMap = new ConcurrentHashMap<>(16); @Override public void registerAlias(String name, String alias) { ... synchronized (this.aliasMap) { // (1) 循环检验: 看是否有和 nam->alias 相反的 alias->name 映射 checkForAliasCircle(name, alias); // (2) 加入HashMap this.aliasMap.put(alias, name); } } - 步骤<1>, 注册 beanName 和 BeanDefinition 的方法是定义在 BeanFactory 内的.
三. Spring Framework bean 的加载
如果是 singleton 的 bean, 尝试从单例缓存中获取
-
如果从单例缓存中没有获取到单例 Bean 对象,则说明两种两种情况:
- 该 Bean 的 scope 不是 singleton
- 该 Bean 的 scope 是 singleton ,但是没有初始化完成。
-
创建 bean 的过程
- 解析指定 BeanDefinition 的 class 属性。
调用 ClassUtil.forName 解析类名为对应的类. 之所以没只用 Class.forName 是因为要解析的类名不只是包名.类名
, 还有各种数组形式类名, 比如:
*java.lang.String[]
类型数组
*[Ljava.lang.String;
类型数组
*[[I
或[[Ljava.lang.String;
类型 - 处理 override 属性。
校验配置的 meta标签, loopup-method标签, replace-method标签 对应的方法是否存在 - 实例化的前置处理。
给BeanPostProcessors
一个机会返回 bean 的代理对象 - 创建 Bean 对象。
(1) 如果配置了工厂方法(可能是静态方法, 也可能是实例方法.):
1. 根据 factory-bean 是否为空, 判断是静态工厂还是实例工厂. 如果是实例工厂, 从beanFactory容器中获取 实例工厂对象
2. 确定构造函数的参数 (3个来源)
(1)explicitArgs 参数:getBean(...)
方法时传递进来的参数, 如果不为空, 就直接用它作为构造函数的参数
(2)配置文件中解析: 配置文件中的信息, 都在BeanDefinition中, 可以从容器缓存的 BeanDefinition Map 中获取对应的 BeanDefinition, 再获取构造参数
3. 获取所有的构造函数
(1) 使用getCandidateMethods
获取类的所有构造方法. (反射)
(2) 对这些构造函数排序 (public的在前, 非public的在后; 构造参数多的在前, 少的在后)
4. 筛选构造函数
(1) 如果配置了 explicitArgs , 直接选取获取参数个数相同
的构造方法
(2) 如果没有配置, 就要调用org.springframework.core.ParameterNameDiscoverer
作构造函数的参数探测
(职责链模式, 先解析javac -parameters
的输出; 没有在调用ASM库解析 class 文件内方法的局部参数列表) https://www.jianshu.com/p/8f5c2daa2b70
(3) 筛选过程, 选择最为接近的构造函数. (参数类型的diffWight最小的构造函数)
* 参数类型相同, diffWight += 0
* 一个是Integer, 一个是Object, 则 diffWight += 2 (Integer的父类是Number, 而Nuber的父类是Object, 需要两层转换)
* 一个是Integer, 一个是Number, 则 diffWight += 1 (因为只有一层父类层级)
5. 创建 bean 实例
(1) 如果配置了 lookup-method, 或 replace-method 属性, 使用 CGLIB 创建对象
(2) 调用org.springframework.beans.factory.support.InstantiationStrategy
接口的instantiate()
实例化 bean
方法内部调用BeanUtils.instantiateClass()
实例化对象 (反射调用了构造函数)
- 解析指定 BeanDefinition 的 class 属性。
在属性填充和初始化之前, 将 singleton 的 bean 放入二级缓存(earlySingletonObjects)和三级缓存(singletonFactories)
填充属性
填充标签中的属性, 这一步进行 byName 或者是 byType 的依赖注入. 直接完成注入(反射调用get方法), 未检测循环依赖, 后面再进行检测
初始化 Bean, 一些列接口
(1)invokeAwareMethods
: 调用一些列 Aware, 对 bean 属性进行设置
* BeanNameAware: setBeanName()
* BeanClassLoaderAware: setBeanClassLoader()
* BeanFactoryAware: setBeanFactory(AbstractAutowireCapableBeanFactory.this)
(2)applyBeanPostProcessorsBeforeInitialization
执行BeanPostProcessor
的postProcessBeforeInitialization()
(3)invokeInitMethods()
* 如果实现了InitializingBean
接口, 则调用afterPropertiesSet()
* 执行标签的方法
(4)applyBeanPostProcessorsAfterInitialization
执行BeanPostProcessor
的postProcessAfterInitialization()
-
解决 bean 之间的循环依赖
https://www.fatalerrors.org/a/how-spring-solves-circular-dependencies.html- 什么是三级缓存?
(1) 一级缓存 singletonObjects: Map: beanName -> 已经构造完毕的 singleton 实例
(2) 二级缓存 earlySingletonObjects: Map: beanName -> 正未初始化完的 bean 实例
(3) 三级缓存 singletonFactories: Map> : beanName -> 未初始化完)的 bean 的 factory - 为什么在被依赖的 bean 构造完成之前, 就先建立依赖关系, 后检测循环构造?
- 什么是三级缓存?
四.ApplicationContext 有什么扩展
- ApplicationContext 实现了多个接口:
-
BeanFactory
:Spring 管理 Bean 的顶层接口,我们可以认为他是一个简易版的 Spring 容器。
ApplicationContext
继承 BeanFactory 的两个子接口:HierarchicalBeanFactory
和ListableBeanFactory
。-
HierarchicalBeanFactory
是一个具有层级关系的 BeanFactory,可以获取父层级 的 BeanFactory 。 -
ListableBeanFactory
可以列举出当前 BeanFactory 中所有的 bean 对象
-
-
ApplicationEventPublisher
:用于封装事件发布功能的接口,向事件监听器(Listener)发送事件消息。 - ResourceLoader:Spring 加载资源的顶层接口,用于从一个源加载资源文件。
ApplicationContext 继承 ResourceLoader 的子接口ResourcePatternResolver
. 该接口是将 location 解析为 Resource 对象的策略接口。 -
MessageSource
:解析 message 的策略接口,用于支撑国际化等功能。 -
EnvironmentCapable
:用于获取 Environment 配置的接口。
-
- 最熟悉的
ClassPathXmlApplicationContext
实现类
ClassPathXmlApplicationContext
类的实现是标准的模板模式- 首先, 一个大而全的接口
ConfigurableApplicationContext
组合了-
ApplicationContext
接口 -
Lifecycle
接口 -
Closeable
接口
-
- 接着, 一个默认的抽象实现类, 实现了
ConfigurableApplicationContext
接口中的公共方法. 代码块中的提示:
//--------------------------------------------------------------------- // Implementation of ApplicationContext interface //--------------------------------------------------------------------- //--------------------------------------------------------------------- // Implementation of Lifecycle interface //--------------------------------------------------------------------- //--------------------------------------------------------------------- // Implementation of ResourcePatternResolver interface //--------------------------------------------------------------------- //--------------------------------------------------------------------- // Implementation of HierarchicalBeanFactory interface //---------------------------------------------------------------------
- 紧接着一些列抽象类, 实现接口中的不同方法, 最后的
ClassPathXmlApplicationContext
类只有构造方法
- 首先, 一个大而全的接口