@ -1,53 +1,55 @@
前面我们主要分析了 FileSystemXmlApplicationContext 这个具体的 IoC 容器的初始化源码实现,在 IoC 容器中建立了 BeanDefinition 的数据映射,将其和 beanName 一起绑定在一个 ConcurrentHashMap 中。现在我们来看一下 spring 是如何将 IoC 容器中的 Bean 根据配置关联在一起的。
## 前言
前面我们主要分析了 FileSystemXmlApplicationContext 这个具体的 IoC容器实现类 的初始化源码,在 IoC容器 中建立了 beanName 到 BeanDefinition 的数据映射,通过一个 ConcurrentHashMap。现在我们来看一下 Spring 是如何将 IoC 容器中存在依赖关系的 bean 根据配置联系在一起的。
Spring 中触发 IoC 容器“依赖注入”的方式有两种,一个是通过 getBean() 向容器索要 bean 时触发依赖注入;另一个是给 bean 配置 lazy-init 属性, spring 会自动调用此 bean 的 getBean() 方法,提前完成依赖注入。总的来说,想提高运行时获取 bean 的效率,可以考虑配置此属性。
Spring 中触发 IoC容器“依赖注入” 的方式有两种,一个是应用程序通过 getBean()方法 向容器索要 bean实例 时触发依赖注入;另一个是提前给 bean 配置了 lazy-init 属性为 false, Spring 在 IoC容器 初始化 会自动调用此 bean 的 getBean() 方法,提前完成依赖注入。总的来说,想提高运行时获取 bean 的效率,可以考虑配置此属性。
下面我将分别解读这两种依赖注入的触发方式,先看 getBean() 的,因为 lazy-init 最后也是通过调用 getBean 完成的依赖注入。
( PS: 可以结合我 GitHub 上对 spring 框架源码的阅读及个人理解一起看,会更有助于各位开发姥爷理解,地址:
下面我将分别解读这两种依赖注入的触发方式,先看 getBean() 的,因为 lazy-init 最后也是通过调用 getBean() 完成的依赖注入。
( PS: 可以结合我 GitHub 上对 Spring 框架源码的阅读及个人理解一起看,会更有助于各位开发姥爷理解,地址:
spring-beans https://github.com/AmyliaY/spring-beans-reading
spring-context https://github.com/AmyliaY/spring-context-reading
)
## 1、AbstractBeanFactory 中的 getBean() 系列方法及 doGetBean() 具体实现
## 正文
首先看一下 AbstractBeanFactory 中的 getBean() 系列方法及 doGetBean() 具体实现。
```java
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
//---------------------------------------------------------------------
// BeanFactory 接口的实现,下列的 getBean() 方法不论是哪种重载,最后都会走
// doGetBean(final String name, final Class< T > requiredType, final Object[] args, boolean typeCheckOnly) 的具体实现
//---------------------------------------------------------------------
// 获取 IOC 容器中指定名称的 B ean
// 获取 IoC容器 中指定名称的 b ean
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
// 获取 IOC 容器中指定名称和类型的 B ean
// 获取 IoC容器 中指定名称和类型的 b ean
public < T > T getBean(String name, Class< T > requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
// 获取 IOC 容器中指定名称和参数的 B ean
// 获取 IoC容器 中指定名称和参数的 b ean
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
// 获取 IOC 容器中指定名称、类型和参数的 B ean
// 获取 IoC容器 中指定名称、类型和参数的 b ean
public < T > T getBean(String name, Class< T > requiredType, Object... args) throws BeansException {
return doGetBean(name, requiredType, args, false);
}
// 真正实现向 IOC 容器获取 Bean 的功能,也是触发依赖注入 (DI) 功能 的地方
// 真正实现向 IoC容器 获取 bean 的功能,也是触发 依赖注入(DI) 的地方
@SuppressWarnings ("unchecked")
protected < T > T doGetBean(final String name, final Class< T > requiredType, final Object[] args,
boolean typeCheckOnly) throws BeansException {
// 根据用户指定的名称获取 IoC 容器中与 BeanDefinition 对应的 beanName
// 如果指定的是别名,则将别名转换为规范的 beanName
// 根据用户给定的名称(也可能是别名alias) 获取 IoC容器 中与 BeanDefinition 唯一对应的 beanName
final String beanName = transformedBeanName(name);
Object bean;
// 先查看缓存中是否有对应的,已创建的单例 Bean, 对于单例 Bean, 整个 IOC 容器中 只创建一次
// 根据 beanName 查看缓存中是否有已实例化的 单例bean, 对于 单例bean, 整个 IoC容器 只创建一次
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null & & args == null) {
if (logger.isDebugEnabled()) {
@ -59,12 +61,12 @@ spring-context https://github.com/AmyliaY/spring-context-reading
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 获取给定 B ean 的实例对象,主要是完成 FactoryBean 的相关处理
// 注意: BeanFactory 本质上是一个 IoC 容器,而 FactoryBean 是 IoC 容器中一种特殊的工厂 bean
// 能够生产其他 对象,注意两者之间的区别
// 获取给定 b ean 的实例对象,主要是完成 FactoryBean 的相关处理
// 注意: BeanFactory 是一个 IoC容器, 它保存了 bean 的基本配置信息。
// 而 FactoryBean 是 IoC容器 中一种特殊的 bean, 它能够实例化 bean 对象,注意两者之间的区别
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// 如果应用程序要获取的 bean 还未创建
else {
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
@ -75,7 +77,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
// 如果当前容器中没有指定的 bean, 且当前容器的父容器不为空
// 则从父容器中去找,如果父容器也没有,则沿着当前容器的继承体系一直向上查找
if (parentBeanFactory != null & & !containsBeanDefinition(beanName)) {
// 解析指定 Bean 名称的原始名称
// 根据用户传入的 name(有可能是别名alias),获取唯一标识的 beanName
String nameToLookup = originalBeanName(name);
if (args != null) {
// 委派父级容器根据指定名称和显式的参数查找
@ -87,9 +89,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
// 创建的 B ean 是否需要进行类型验证,一般不需要
// 创建的 b ean 是否需要进行类型验证,一般不需要
if (!typeCheckOnly) {
// 向容器标记指定的 B ean 已经被创建
// 向容器标记指定的 b ean 已经被创建
markBeanAsCreated(beanName);
}
@ -98,26 +100,28 @@ spring-context https://github.com/AmyliaY/spring-context-reading
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 获取当前 Bean 依赖的所有 Bean, 下面的 getBean(dependsOnBean) 方法会触发 getBean() 的递归调用,
// 直到取到一个不依赖任何其它 bean 的 bean 为止
// 获取当前 bean 所依赖bean 的 beanName, 下面的 getBean(dependsOnBean) 方法会触发
// getBean() 的递归调用,直到取到一个不依赖任何其它 bean 的 bean 为止。
// 比如: beanA 依赖了 beanB, 而 beanB 依赖了 beanC, 那么在实例化 beanA 时会先实例化
// beanC, 然后实例化 beanB 并将 beanC 注入进去,最后实例化 beanA 时将 beanB 注入
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
// 递归调用 getBean() 方法,获取当前 Bean 所依赖的 bean
// 递归调用 getBean() 方法,从末级节点依次实例化 依赖的 bean
getBean(dependsOnBean);
// 把当前 bean 所依赖的 bean 进行注入
// 把 当前bean 直接依赖的bean 进行注册
//(也就是通过 setter 或构造方法将依赖的 bean 赋值给当前 bean 对应的属性)
registerDependentBean(dependsOnBean, beanName);
}
}
// 创建单例模式 bean 的实例对象
// 如果当前 bean 是单例的
if (mbd.isSingleton()) {
// 这里使用了一个匿名内部类,创建 Bean 实例对象,并且注册给所依赖的 对象
// 这里使用了一个匿名内部类,创建 bean实例 对象
sharedInstance = getSingleton(beanName, new ObjectFactory< Object > () {
public Object getObject() throws BeansException {
try {
// 创建一个指定 Bean 实例对象,如果有父级继承,则合并子类和父类的定义
// 根据给定的 beanName 及 RootBeanDefinition对象, 创建 bean 实例对象
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
@ -126,41 +130,42 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
});
// 获取给定 B ean 的实例对象
// 获取给定 b ean 的实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// IoC 容器创建原型模式 B ean 实例对象
// 创建原型模式的 b ean 实例对象
else if (mbd.isPrototype()) {
// 原型模式 (Prototype) 是 每次都会创建一个新的对象
// 原型模式 (Prototype) 每次都会创建一个新的对象
Object prototypeInstance = null;
try {
// 回调 beforePrototypeCreation 方法,默认的功能是注册当前创建的原型对象
// 回调 beforePrototypeCreation() 方法,默认的功能是注册当前创建的原型对象
beforePrototypeCreation(beanName);
// 创建指定 B ean 对象实例
// 创建指定 b ean 对象实例
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// 回调 afterPrototypeCreation 方法,默认的功能告诉 IoC 容器指定 Bean 的原型对象不再创建了
// 回调 afterPrototypeCreation() 方法,默认的功能是告诉 IoC容器
// 指定 bean 的原型对象不再创建了
afterPrototypeCreation(beanName);
}
// 获取给定 B ean 的实例对象
// 获取给定 b ean 的实例对象
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 要创建的 Bean 既不是单例模式,也不是原型模式,则根据 Bean 定义资源 中
// 配置的生命周期范围,选择实例化 B ean 的合适方法,这种在 Web 应用程序中
// 要创建的 bean 既不是单例模式,也不是原型模式,则根据该 bean元素 在配置文件 中
// 配置的生命周期范围,选择实例化 b ean 的合适方法,这种在 Web 应用程序中
// 比较常用, 如: request、session、application 等的生命周期
else {
// 获取此 bean 生命周期的范围
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
// Bean 定义资源中没有配置生命周期范围,则 Bean 定义 不合法
// bean 定义资源中没有配置生命周期范围,则该 bean 的配置 不合法
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
// 这里又使用了一个 匿名内部类,获取一个指定生命周期范围的实例
// 这里又使用了一个 ObjectFactory 的 匿名内部类,获取一个指定生命周期范围的实例
Object scopedInstance = scope.get(beanName, new ObjectFactory< Object > () {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
@ -172,7 +177,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
});
// 获取给定 B ean 的实例对象
// 获取给定 b ean 的实例对象
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
@ -189,7 +194,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
// 对创建的 bean 实例对象 进行非空验证和类型检查,如果没问题就返回这个已经完成依赖注入的 bean
// 对要返回的 bean实例对象 进行非空验证和类型检查,如果没问题就返回这个已经完成 依赖注入的bean
if (requiredType != null & & bean != null & & !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
@ -204,12 +209,16 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
return (T) bean;
}
}
```
总的来说, getBean() 方法是依赖注入的起点,之后会调用 createBean(),根据 BeanDefinition 的定义生成 bean 对象,下面我们看看 AbstractBeanFactory 的子类 AbstractAutowireCapableBeanFactory 中对 createBean() 的具体实现。
## 2、AbstractAutowireCapableBeanFactory 中的 createBean() 和 doCreateBean() 具体实现
总的来说, getBean() 方法是依赖注入的起点,之后会调用 createBean(),根据之前解析生成的 BeanDefinition对象 生成 bean 对象,下面我们看看 AbstractBeanFactory 的子类 AbstractAutowireCapableBeanFactory 中对 createBean() 的具体实现。
```java
// 创建指定的 bean 实例对象
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
/**
* 创建指定的 bean 实例对象
*/
@Override
protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
@ -217,11 +226,11 @@ spring-context https://github.com/AmyliaY/spring-context-reading
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
// 判断需要创建的 Bean 是否可以 实例化,是否可以通过当前的类加载器加载
// 判断需要创建的 bean 是否可 实例化,是否可以通过当前的类加载器加载
resolveBeanClass(mbd, beanName);
try {
// 校验和准备 B ean 中的方法覆盖
// 校验和准备 b ean 中的方法覆盖
mbd.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
@ -230,7 +239,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
try {
// 如果 B ean 配置了后置处理器 PostProcessor, 则这里返回一个 proxy 代理对象
// 如果 b ean 配置了后置处理器 PostProcessor, 则这里返回一个 proxy 代理对象
Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
return bean;
@ -241,7 +250,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
"BeanPostProcessor before instantiation of bean failed", ex);
}
// 创建 B ean 实例对象的具体实现
// 创建 b ean 实例对象的具体实现
Object beanInstance = doCreateBean(beanName, mbd, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
@ -249,17 +258,17 @@ spring-context https://github.com/AmyliaY/spring-context-reading
return beanInstance;
}
// 创建 Bean 实例对象的具体实现, spring 中以 do 开头的都是方法的具体实现
/**
* 创建 bean 实例对象的具体实现, Spring 中以 do 开头的都是方法的具体实现
*/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
// 封装被创建的 Bean 对象
BeanWrapper instanceWrapper = null;
// 如果这个 bean 是单例的,则从缓存中获取这个 BeanWrapper 实例并清除
// 如果这个 bean 是单例的,则从缓存中获取这个 beanName 对应的 BeanWrapper实例, 并清除
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
/**
* ! ! ! ! ! ! ! ! ! ! ! ! !
* 创建实例对象
@ -280,7 +289,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
// 向容器中缓存单例模式的 B ean 对象,以防循环引用
// 向容器中缓存单例模式的 b ean 对象,以防循环引用
boolean earlySingletonExposure = (mbd.isSingleton() & & this.allowCircularReferences & &
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
@ -288,7 +297,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 这里是一个 匿名内部类,为了防止循环引用,尽早持有对象的引用
// 这里是一个 ObjectFactory 的 匿名内部类,为了防止循环引用,尽早持有对象的引用
addSingletonFactory(beanName, new ObjectFactory< Object > () {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
@ -296,8 +305,8 @@ spring-context https://github.com/AmyliaY/spring-context-reading
});
}
// B ean 对象的初始化,依赖注入在此触发
// 这个 exposedObject 在初始化完成之后,将返回作为依赖注入完成后的 B ean
// b ean 对象的初始化,依赖注入在此触发
// 这个 exposedObject 在初始化完成之后,将返回作为依赖注入完成后的 b ean
Object exposedObject = bean;
try {
/**
@ -307,9 +316,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
*/
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// 初始化 Bean 对象
// 在对 Bean 实例对象生成和依赖注入完成以后,开始对 Bean 实例对象
// 进行初始化 ,为 Bean 实例对象应用 BeanPostProcessor 后置处理器
// 初始化 bean对象
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
@ -323,21 +330,21 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
if (earlySingletonExposure) {
// 获取指定名称的已注册的单例模式 Bean 对象
// 获取指定名称的已注册的 单例bean 对象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 如果根据名称获取的已注册的 Bean 和正在实例化的 B ean 是同一个
// 如果根据名称获取的已注册的 bean 和正在实例化的 b ean 是同一个
if (exposedObject == bean) {
// 当前实例化的 B ean 初始化完成
// 当前实例化的 b ean 初始化完成
exposedObject = earlySingletonReference;
}
// 如果当前 Bean 依赖其他 B ean, 并且当发生循环引用时不允许新创建实例对象
// 如果当前 bean 依赖其他 b ean, 并且当发生循环引用时不允许新创建实例对象
else if (!this.allowRawInjectionDespiteWrapping & & hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set< String > actualDependentBeans = new LinkedHashSet< String > (dependentBeans.length);
// 获取当前 Bean 所依赖的其他 B ean
// 获取当前 bean 所依赖的其他 b ean
for (String dependentBean : dependentBeans) {
// 对依赖 B ean 进行类型检查
// 对 依赖b ean 进行类型检查
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
@ -356,7 +363,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
try {
// 注册完成依赖注入的 B ean
// 注册 成完依赖注入的b ean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
@ -366,23 +373,23 @@ spring-context https://github.com/AmyliaY/spring-context-reading
// 为应用返回所需要的实例对象
return exposedObject;
}
}
```
从源码中可以看到 createBeanInstance() 和 populateBean() 这两个方法与依赖注入的实现非常密切, createBeanInstance() 方法中生成了 Bean 所包含的 Java 对象, populateBean() 方法对这些生成的 bean 对象之间的依赖关系进行了处理。下面我们先看一下 createBeanInstance() 方法的实现。
## 3、createBeanInstance() 方法的具体实现
从源码中可以看到 createBeanInstance() 和 populateBean() 这两个方法与依赖注入的实现非常密切, createBeanInstance() 方法中生成了 bean 所包含的 Java 对象, populateBean() 方法对这些生成的 bean 对象之间的依赖关系进行了处理。下面我们先看一下 createBeanInstance() 方法的实现。
```java
// 创建 Bean 的实例对象
/**
* 创建 bean 的实例对象
*/
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// 检查确认 B ean 是可实例化的
// 检查确认 b ean 是可实例化的
Class< ?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null & & !Modifier.isPublic(beanClass.getModifiers()) & & !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
// 使用工厂方法对 B ean 进行实例化
// 使用 RootBeanDefinition对象 中的 factoryMethodName 对 b ean 进行实例化
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
@ -400,8 +407,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
if (resolved) {
if (autowireNecessary) {
// 配置了自动装配属性,使用容器的自动装配实例化,
// 即,根据参数类型匹配 Bean 的构造方法
// 配置了自动装配属性,使用容器的自动装配实例化,即,根据参数类型匹配 bean 的构造方法
return autowireConstructor(beanName, mbd, null, null);
}
else {
@ -410,7 +416,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
// 使用 B ean 的构造方法进行实例化
// 使用 b ean 的构造方法进行实例化
Constructor< ?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
@ -422,14 +428,14 @@ spring-context https://github.com/AmyliaY/spring-context-reading
return instantiateBean(beanName, mbd);
}
// 使用默认的无参构造方法实例化 Bean 对象
// 使用默认的无参构造方法实例化 bean 对象
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
// 获取系统的安全管理接口, JDK 标准的安全管理 API
if (System.getSecurityManager() != null) {
// 这里是一个匿名内置 类,根据实例化策略创建实例对象
// 这里使用了一个 PrivilegedAction 的匿名内部 类,根据实例化策略创建实例对象
beanInstance = AccessController.doPrivileged(new PrivilegedAction< Object > () {
public Object run() {
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
@ -437,10 +443,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}, getAccessControlContext());
}
else {
/**
* ! ! ! ! ! ! ! ! ! ! ! ! ! !
* 使用初始化策略实例化 B ean 对象
* 使用初始化策略实例化 b ean 对象
* ! ! ! ! ! ! ! ! ! ! ! ! ! !
*/
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
@ -453,23 +458,22 @@ spring-context https://github.com/AmyliaY/spring-context-reading
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
```
从源码中我们可以看到其调用了 SimpleInstantiationStrategy 实现类来生成 bean 对象,这个类是 spring 用来生成 bean 对象的默认类,它提供了两种策略来实例化 bean 对象,一种是利用 Java 的反射机制,另一种是直接使用 CGLIB。
## 4、SimpleInstantiationStrategy 中的 instantiate() 方法实现
从源码中我们可以看到其调用了 SimpleInstantiationStrategy 实现类来生成 bean 对象,这个类是 Spring 用来生成 bean对象 的默认类,它提供了两种策略来实例化 bean对象, 一种是利用 Java 的反射机制,另一种是直接使用 CGLIB。
```java
// 使用初始化策略实例化 Bean 对象
public class SimpleInstantiationStrategy implements InstantiationStrategy {
// 使用初始化策略实例化 bean对象
public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
// 如果 Bean 定义中没有方法覆盖,则使用 Java 的反射机制实例化对象,否则使用 CGLIB
// 如果 配置的bean 中没有方法覆盖,则使用 Java 的反射机制实例化对象,否则使用 CGLIB
if (beanDefinition.getMethodOverrides().isEmpty()) {
Constructor< ?> constructorToUse;
synchronized (beanDefinition.constructorArgumentLock) {
// 获取对象的构造方法或生成对象的工厂 方法对 bean 进行实例化
// 获取对象的构造 方法对 bean 进行实例化
constructorToUse = (Constructor< ?>) beanDefinition.resolvedConstructorOrFactoryMethod;
// 如果前面没有获取到构造方法,则通过反射获取
if (constructorToUse == null) {
// 使用 JDK 的反射机制,判断要实例化的 B ean 是否是接口
// 使用 JDK 的反射机制,判断要实例化的 b ean 是否是接口
final Class clazz = beanDefinition.getBeanClass();
// 如果 clazz 是一个接口,直接抛出异常
if (clazz.isInterface()) {
@ -477,7 +481,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
try {
if (System.getSecurityManager() != null) {
// 这里是一个匿名内置类,使用反射机制获取 B ean 的构造方法
// 这里使用了一个 PrivilegedExceptionAction 的匿名内部类,使用反射机制获取 b ean 的构造方法
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction< Constructor > () {
public Constructor run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
@ -494,7 +498,8 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
}
// 使用 BeanUtils 实例化,通过反射机制调用”构造方法.newInstance(arg)”来进行实例化
// 根据传入的 Constructor, 在 BeanUtils 中调用该 Constructor 的
// newInstance(Object...) 方法,实例化指定对象
return BeanUtils.instantiateClass(constructorToUse);
}
else {
@ -507,17 +512,19 @@ spring-context https://github.com/AmyliaY/spring-context-reading
return instantiateWithMethodInjection(beanDefinition, beanName, owner);
}
}
}
```
在 SimpleInstantiationStrategy 的子类 CglibSubclassingInstantiationStrategy 中可以看到使用 CGLIB 进行实例化的源码实现。
## 5、CglibSubclassingInstantiationStrategy 中使用 CGLIB 进行实例化的源码实现
```java
// 下面两个方法都通过实例化自己的私有静态内部类 CglibSubclassCreator,
// 然后调用该内部类对象的实例化方法 instantiate() 完成实例化
public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy {
/**
* 下面两个方法都通过实例化自己的私有静态内部类 CglibSubclassCreator,
* 然后调用该内部类对象的实例化方法 instantiate() 完成实例化
*/
protected Object instantiateWithMethodInjection(
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
// 必须生成 cglib 子类
return new CglibSubclassCreator(beanDefinition, owner).instantiate(null, null);
}
@ -545,11 +552,11 @@ spring-context https://github.com/AmyliaY/spring-context-reading
this.owner = owner;
}
// 使用 CGLIB 进行 Bean 对象 实例化
// 使用 CGLIB 进行 bean对象 实例化
public Object instantiate(Constructor ctor, Object[] args) {
// 实例化 Enhancer对象, 并为 Enhancer对象 设置父类,生成 Java 对象的参数,比如:基类、回调方法等
Enhancer enhancer = new Enhancer();
// 将 B ean 本身作为其父类
// 将 b ean 本身作为其父类
enhancer.setSuperclass(this.beanDefinition.getBeanClass());
enhancer.setCallbackFilter(new CallbackFilterImpl());
enhancer.setCallbacks(new Callback[] {
@ -558,33 +565,38 @@ spring-context https://github.com/AmyliaY/spring-context-reading
new ReplaceOverrideMethodInterceptor()
});
// 使用 CGLIB 的 create 方法生成实例对象
// 使用 CGLIB 的 create() 方法生成实例对象
return (ctor == null) ? enhancer.create() : enhancer.create(ctor.getParameterTypes(), args);
}
}
}
```
至此,完成了 bean 对象的实例化,然后就可以根据解析得到的 BeanDefinition 完成对各个属性的赋值处理,也就是依赖注入。这个实现方法就是前面 AbstractAutowireCapableBeanFactory 类中的 populateBean() 方法。
## 6、AbstractAutowireCapableBeanFactory 中的 populateBean(),完成依赖注入
至此,完成了 bean对象 的实例化,然后就可以根据解析得到的 BeanDefinition对象 完成对各个属性的赋值处理,也就是依赖注入。这个实现方法就是前面 AbstractAutowireCapableBeanFactory 类中的 populateBean() 方法。
```java
// 为属性赋值,完成依赖注入
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
/**
* 为属性赋值,完成依赖注入
*/
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
// 获取 BeanDefinition 中设置的 property, 这些 property 来自对 BeanDefinition 的解析
// 获取 RootBeanDefinition 中设置的 属性值PropertyValues, 这些属性值来自对
// .xml 文件中 bean元素 的解析
PropertyValues pvs = mbd.getPropertyValues();
// 如果实例对象为 null, 而要注入的属性值不为空, 则抛出下述异常
// 如果 BeanWrapper对象 为 null, 而要注入的属性值不为空, 则抛出下述异常
if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// 实例对象 为 null, 属性值也为空, 不需要设置属性值, 直接返回
// BeanWrapper对象 为 null, 属性值也为空, 不需要设置属性值, 直接返回
return;
}
}
// 在设置属性之前调用 B ean 的 PostProcessor 后置处理器
// 在设置属性之前调用 b ean 的 PostProcessor 后置处理器
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() & & hasInstantiationAwareBeanPostProcessors()) {
@ -608,12 +620,12 @@ spring-context https://github.com/AmyliaY/spring-context-reading
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 对 autowire 自动装配的处理,根据 B ean 名称自动装配注入
// 对 autowire 自动装配的处理,根据 b ean 名称自动装配注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 根据 B ean 类型自动装配注入
// 根据 b ean 类型自动装配注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
@ -621,9 +633,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
pvs = newPvs;
}
// 检查容器是否持有用于处理单例模式 B ean 关闭时的后置处理器
// 检查容器是否持有用于处理单例模式 b ean 关闭时的后置处理器
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// Bean 实例对象 没有依赖,即没有继承基类
// bean实例对象 没有依赖,即没有继承基类
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
@ -654,7 +666,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
applyPropertyValues(beanName, mbd, bw, pvs);
}
// 解析并注入依赖属性的过程
/**
* 解析并注入依赖属性的过程
*/
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs == null || pvs.isEmpty()) {
return;
@ -697,7 +711,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
if (converter == null) {
converter = bw;
}
// 创建一个 BeanDefinition 属性值解析器,将 Bean 定义中的属性值解析为 B ean 实例对象的实际值
// 创建一个 BeanDefinition 属性值解析器,将 BeanDefinition 中的属性值解析为 b ean 实例对象的实际值
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// 为属性的解析值创建一个副本,最后将属性值注入到实例对象中
@ -771,15 +785,17 @@ spring-context https://github.com/AmyliaY/spring-context-reading
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
}
```
## 7、BeanDefinitionValueResolver 中解析属性值,对注入类型进行转换的具体实现
BeanDefinitionValueResolver 中解析属性值,对注入类型进行转换的具体实现。
```java
// 解析属性值,对注入类型进行转换
class BeanDefinitionValueResolver {
/**
* 解析属性值,对注入类型进行转换
*/
public Object resolveValueIfNecessary(Object argName, Object value) {
// 对引用类型的属性进行解析, RuntimeBeanReference 是在对
// BeanDefinition 进行解析时生成的数据对象
// 对引用类型的属性进行解析, RuntimeBeanReference 是在对 BeanDefinition 进行解析时生成的数据对象
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
/**
@ -790,7 +806,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
return resolveReference(argName, ref);
}
// 对属性值是引用容器中另一个 B ean 名称的解析
// 对属性值是引用容器中另一个 b ean 名称的解析
else if (value instanceof RuntimeBeanNameReference) {
String refName = ((RuntimeBeanNameReference) value).getBeanName();
refName = String.valueOf(evaluate(refName));
@ -800,7 +816,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
return refName;
}
// 对 BeanDefinitionHolder 类型属性的解析,主要是 B ean 中的内部类
// 对 BeanDefinitionHolder 类型属性的解析,主要是 b ean 中的内部类
else if (value instanceof BeanDefinitionHolder) {
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
@ -898,10 +914,12 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
// 解析引用类型的属性值
/**
* 解析引用类型的属性值
*/
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
// 获取引用的 B eanName
// 获取 所引用bean 的 b eanName
String refName = ref.getBeanName();
refName = String.valueOf(evaluate(refName));
// 如果引用的对象在父容器中,则从父容器中获取指定的引用对象
@ -914,11 +932,11 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
return this.beanFactory.getParentBeanFactory().getBean(refName);
}
// 从当前的容器中获取指定的引用 Bean 对象,如果指定的 B ean 没有被实例化
// 则会递归触发引用 B ean 的初始化和依赖注入
// 从当前的容器中获取指定的引用 bean对象, 如果指定的 b ean 没有被实例化
// 则会递归触发引用 b ean 的初始化和依赖注入
else {
Object bean = this.beanFactory.getBean(refName);
// 为 refName 对应的 BeanDefinition 注入依赖的 B ean
// 为 refName对应的bean 注入 它所依赖的b ean
this.beanFactory.registerDependentBean(refName, this.beanName);
return bean;
}
@ -930,7 +948,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
// 解析 array 类型的属性
/**
* 解析 array 类型的属性
*/
private Object resolveManagedArray(Object argName, List<?> ml, Class<?> elementType) {
// 创建一个指定类型的数组,用于存放和返回解析后的数组
Object resolved = Array.newInstance(elementType, ml.size());
@ -942,7 +962,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
return resolved;
}
// 解析 list 类型的属性
/**
* 解析 list 类型的属性
*/
private List resolveManagedList(Object argName, List< ?> ml) {
List< Object > resolved = new ArrayList< Object > (ml.size());
for (int i = 0; i < ml.size ( ) ; i + + ) {
@ -953,7 +975,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
return resolved;
}
// 解析 set 类型的属性
/**
* 解析 set 类型的属性
*/
private Set resolveManagedSet(Object argName, Set< ?> ms) {
Set< Object > resolved = new LinkedHashSet< Object > (ms.size());
int i = 0;
@ -965,7 +989,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
return resolved;
}
// 解析 map 类型的属性
/**
* 解析 map 类型的属性
*/
private Map resolveManagedMap(Object argName, Map<?, ?> mm) {
Map< Object , Object > resolved = new LinkedHashMap< Object , Object > (mm.size());
// 递归解析 map 中每一个元素的 key 和 value
@ -977,11 +1003,24 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
return resolved;
}
}
```
至此,已经为依赖注入做好了准备,下面就该将 bean 对象设置到它所依赖的另一个 bean 的属性中去。AbstractPropertyAccessor 和其子类 BeanWrapperImpl 完成了依赖注入的详细过程。
## 8、AbstractPropertyAccessor 中的实现
至此,已经为依赖注入做好了准备,下面就该将 bean对象 设置到它所依赖的另一个 bean 的属性中去。AbstractPropertyAccessor 和其子类 BeanWrapperImpl 完成了依赖注入的详细过程。先看一下 AbstractPropertyAccessor 中的实现。
```java
public abstract class AbstractPropertyAccessor extends TypeConverterSupport implements ConfigurablePropertyAccessor {
/**
* setPropertyValues() 方法有多种重载,但最终都走的是
* setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)重载方法
*/
public void setPropertyValues(Map<?, ?> map) throws BeansException {
setPropertyValues(new MutablePropertyValues(map));
}
public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown) throws BeansException {
setPropertyValues(pvs, ignoreUnknown, false);
}
public void setPropertyValues(PropertyValues pvs) throws BeansException {
setPropertyValues(pvs, false, false);
}
@ -996,7 +1035,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
try {
/**
* ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
* 走 BeanWrapperImpl 中的实现,也是 bean 属性值注入 具体实现的入口
* 该方法走 BeanWrapperImpl 中的实现,这是 bean属性值注入 具体实现的入口
* ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
*/
setPropertyValue(pv);
@ -1019,18 +1058,20 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
// 如果遇到个别异常,则抛出复合异常
// 如果出现 PropertyAccessException 异常,则将这些异常积累起来放到一个集合中,然后一次性抛出!!!
// 这种抛异常的方式 在实际的开发中也时常使用,可以好好看一下,对比一下
if (propertyAccessExceptions != null) {
PropertyAccessException[] paeArray =
propertyAccessExceptions.toArray(new PropertyAccessException[propertyAccessExceptions.size()]);
throw new PropertyBatchUpdateException(paeArray);
}
}
}
```
## 9、BeanWrapperImpl 中的实现
最后看一下 BeanWrapperImpl 中的实现。
```java
public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWrapper {
@Override
public void setPropertyValue(PropertyValue pv) throws BeansException {
// PropertyTokenHolder 是一个用于内部使用的内部类
@ -1064,17 +1105,17 @@ spring-context https://github.com/AmyliaY/spring-context-reading
/**
* ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
* 实现属性值依赖注入 的具体实现
* 依赖注入( 将某个bean所依赖的值 注入到这个bean中) 的具体实现
* ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
*/
@SuppressWarnings ("unchecked")
private void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
// PropertyTokenHolder 主要保存属性的名称、路径、以及集合的 size 等信息
// PropertyTokenHolder 是定义在 BeanWrapperImpl 中的内部类,主要保存属性的名称、路径、
// 以及集合的 size 等信息
String propertyName = tokens.canonicalName;
String actualName = tokens.actualName;
// 对集合类型的属性注入
// keys 是用来保存集合类型属性的 size
// 对集合类型的属性注入, PropertyTokenHolder 的 keys 是用来保存集合类型属性的 size
if (tokens.keys != null) {
// 将属性信息从 tokens 拷贝到 getterTokens
PropertyTokenHolder getterTokens = new PropertyTokenHolder();
@ -1284,7 +1325,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
// 根据 Java 的内省机制,获取属性的 setter(写方法) 方法
// 根据 Java 的内省机制,获取属性的 setter方法
final Method writeMethod = (pd instanceof GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodForActualAccess() :
pd.getWriteMethod());
@ -1343,27 +1384,35 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
}
}
```
终于 完成了对 bean 的各种属性的依赖注入,在 bean 的实例化和依赖注入的过程中,需要依据 BeanDefinition 中的信息来递归地完成依赖注入。另外,在此过程中存在许多递归调用,一个递归是在上下文体系中查找需要的 bean 和创建 bean 的递归调用;另一个是在依赖注入时,通过递归调用容器的 getBean 方法,得到当前 bean 的依赖 bean, 同时也触发对依赖 bean 的创建和注入;在对 bean 的属性进行依赖注入时,解析的过程也是递归的。这样,根据依赖关系,一层一层地完成 bean 的创建和注入,直到最后完成当前 bean 的创建。
至此, 完成了对 bean 的各种属性的依赖注入,在 bean 的实例化和依赖注入的过程中,需要依据 BeanDefinition 中的信息来递归地完成依赖注入。另外,在此过程中存在许多递归调用,一个递归是在上下文体系中查找 当前bean依赖的 bean 和创建 当前bean依赖的 bean 的递归调用;另一个是在依赖注入时,通过递归调用容器的 getBean() 方法,得到当前 bean 的依赖 bean, 同时也触发对依赖 bean 的创建和注入;在对 bean 的属性进行依赖注入时,解析的过程也是递归的。这样,根据依赖关系, 从最末层的依赖bean开始 ,一层一层地完成 bean 的创建和注入,直到最后完成当前 bean 的创建。
## 最后补充一下通过 lazy-init 属性触发的依赖注入
lazy-init 触发的预实例化和依赖注入,发生在 IoC 容器完成对 BeanDefinition 的定位、载入、解析和注册之后。虽然会影响 IoC 容器初始化的性能,但确能有效提高 应用第一次获取该 bean 的效率。
## lazy-init 属性触发的依赖注入
最后看一下 lazy-init 触发的预实例化和依赖注入,发生在 IoC 容器完成对 BeanDefinition 的定位、载入、解析和注册之后。通过牺牲 IoC 容器初始化的性能,来有效提升 应用第一次获取该 bean 的效率。
lazy-init 实现的入口方法在我们前面解读过的 AbstractApplicationContext 的 refresh() 中,它是 IoC 容器正式启动的标志。
```java
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean {
/**
* 容器初始化的过程: BeanDefinition 的 Resource 定位、BeanDefinition 的载入、BeanDefinition 的注册。
* BeanDefinition 的载入和 bean 的依赖注入是两个独立的过程,依赖注入一般发生在 应用第一次通过 getBean() 方法从容器获取 bean 时。
* 容器初始化的过程:
* 1、根据指定规则扫描指定目录, 获取所有 用于配置bean的配置文件;
* 2、根据 Spring定义的规则, 解析配置文件中的各个元素, 将其封装成 IoC容器 可以装载的 BeanDefinition对象;
* 3、将封装好的 BeanDefinition 注册进 IoC容器。
*
* 另外需要注意的是, IoC 容器有一个预实例化的配置(即,将 AbstractBeanDefinition 中的 lazyInit 属性设为 true) , 使用户可以对容器的初始化
* 过程做一个微小的调控, lazyInit 设为 true 的 bean 将在容器初始化时进行依赖注入,而不会等到 getBean() 方法调用时才进行
* IoC容器的初始化 和 bean的依赖注入 是两个独立的过程,依赖注入一般发生在应用第一次通过 getBean()方法
* 从容器获取 bean 时。
* 另外需要注意的是, IoC容器 有一个预实例化的配置(即,将 < bean > 元素 的 lazyInit属性 设为 false) ,
* 使该 < bean > 元素对应的 bean可以提前实例化, 而不用等到调用 getBean()方法 时才开始实例化。
*/
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 调用容器准备刷新的方法,获取容器的当前时间,同时给容器设置同步标识
prepareRefresh();
// 告诉子类启动 refreshBeanFactory() 方法, Bean 定义资源文件的载入从子类的 refreshBeanFactory() 方法启动开始
// 告诉子类启动 refreshBeanFactory() 方法, BeanDefinition 资源文件的载入从子类的
// refreshBeanFactory() 方法启动开始
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 为 BeanFactory 配置容器特性,例如类加载器、事件处理器等
@ -1373,7 +1422,7 @@ lazy-init 触发的预实例化和依赖注入,发生在 IoC 容器完成对 B
// 为容器的某些子类指定特殊的 BeanPost 事件处理器
postProcessBeanFactory(beanFactory);
// 调用所有注册的 BeanFactoryPostProcessor 的 Bean
// 调用所有注册的 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 为 BeanFactory 注册 BeanPost 事件处理器.
@ -1394,7 +1443,7 @@ lazy-init 触发的预实例化和依赖注入,发生在 IoC 容器完成对 B
/**
* ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
* 初始化 Bean, 并对 lazy-init 属性进行处理
* 对配置了 lazy-init属性为true的bean 进行预实例化
* ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
*/
finishBeanFactoryInitialization(beanFactory);
@ -1415,16 +1464,18 @@ lazy-init 触发的预实例化和依赖注入,发生在 IoC 容器完成对 B
}
}
// 对配置了 lazy-init 属性的 Bean 进行预实例化处理
/**
* 对配置了 lazy-init属性为true的bean 进行预实例化
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 这是 Spring3 以后新加的代码,为容器指定一个转换服务 (ConversionService)
// 在对某些 B ean 属性进行转换时使用
// 在对某些 b ean 属性进行转换时使用
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) & &
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
/**
* ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
* 在这里调用了 getBean() 方法,触发依赖注入
* 在这里 通过调用 getBean() 方法,触发依赖注入
* ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
*/
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
@ -1441,8 +1492,8 @@ lazy-init 触发的预实例化和依赖注入,发生在 IoC 容器完成对 B
// 缓存容器中所有注册的 BeanDefinition 元数据,以防被修改
beanFactory.freezeConfiguration();
// 对配置了 lazy-init 属性的单态模式 B ean 进行预实例化处理
// 对配置了 lazy-init属性 的 单例b ean 进行预实例化处理
beanFactory.preInstantiateSingletons();
}
}
```