缘起

​上一篇​​中我们讲述了IOC容器的实现原理,我们知道IOC容器实际上就是把我们的Bean封装成一个BeanDefinition然后放入到一个map中,那么本篇主要讲述我们如何使用这个Bean,也就是所谓的依赖注入(DI)。

DI的实现原理

我们还是写这样一个简单的main方法来测试

Spring中的DI的实现原理_sed

getBean方法最终会调用AbstractBeanFactory类的getBean方法

Spring中的DI的实现原理_实例化_02

看doGetBean方法,该方法由于太长,截图没法截全,所以就放代码了

//真正实现向IOC容器获取Bean的功能,也是触发依赖注入功能的地方
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

//根据指定的名称获取被管理Bean的名称,剥离指定名称中对容器的相关依赖
//如果指定的是别名,将别名转化为规范的Bean名称
final String beanName = transformedBeanName(name);
Object bean;

// Eagerly check singleton cache for manually registered singletons.
//先从缓存中取得是否已经有被创建过的单态类型的Bean
//对于单例模式的Bean整个IOC容器只创建一次,不需要重复创建
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//获取Bean实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
//如果缓存中没有取得单例模式的Bean,则进行以下步骤
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
//缓存没有正在创建的单例模式Bean
//缓存中已经有已经创建的原型模式Bean
//但是由于循环引用的问题导致实例化对象失败
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}

// Check if bean definition exists in this factory.
//对IOC容器中是否存在指定名称的BeanDefinition进行检查,
// 首先检查是否能在当前的BeanFactory中获取到所需要的Bean,
// 如果不能则委托当前容器的父级容器去查找,
// 如果还是找不到则沿着容器的继承体系向父级容器查找
BeanFactory parentBeanFactory = getParentBeanFactory();
//档期容器的父级容器存在,且当前容器中不存在指定名称的Bean
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
//解析指定Bean名称的原始名称
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
//委派父级容器根据指定名称和显示的参数查找
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
//委派父级容器根据指定名称和类型查找
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}

//创建的Bean是否需要进行类型验证,一般不需要
if (!typeCheckOnly) {
//向容器标记指定的Bean已经被创建
markBeanAsCreated(beanName);
}

try {
//根据指定Bean名称获取其父级的Bean定义
//主要解决Bean继承时子类合并父类公共属性问题
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);

// Guarantee initialization of beans that the current bean depends on.
//获取当前Bean所有依赖Bean的名称
String[] dependsOn = mbd.getDependsOn();
//如果当前Bean有依赖Bean
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}

// 把依赖Bean注册给当前的Bean
registerDependentBean(dep, beanName);
try {

// 递归调用, 获取当前Bean的依赖Bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}

// Create bean instance.
// 创建单例模式Bean的实例对象
if (mbd.isSingleton()) {
//这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
sharedInstance = getSingleton(beanName, () -> {
try {
//创建一个指定Bean实例对象,如果有父级继承,则合并子类和父类
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
//清楚该单例
destroySingleton(beanName);
throw ex;
}
});
//获取给定Bean的实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 创建原型模式Bean的实例对象
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 如果创建的bean 不是单例也不是原型, 则根据声明周期选择实例化bean的方法
// 如 request session 等不同范围的实例
else {
String scopeName = mbd.getScope();
// 如果 scope 是空, 则抛异常
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
//否则
try {
//获取一个指定了scope的bean实例
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}

// Check if required type matches the type of the actual bean instance.
//检查是否需要类型检测
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}

这个方法主要做了三件事情(该部分摘抄至:​​Java知音​​)


  1. 根据传来的 bean的 name(有可能是别名)来获取真正的 bean名称: beanName
  2. 根据 beanName获取单例实例,如果有直接获取到 bean实例并返回,DI完成。
  3. 如果根据 beanName没有获得到单例实例:则做如下操作
    ​3.1 判断是不是原型实例,如果是,则抛出创建失败异常,如果不是,下一步。 3.2 检查 BeanDefinition 是否在当前的容器中,如果不在那可能在父类容器中,所以委托父类容器查找,如果还没有,则再上一级容器...递归查找。 3.3 检查这个实例是否是为了类型检查而获取,而不是用来使用,如果是,标记这个bean已经被创建,如果不是,下一步。 3.4 根据 beanName获取 父类的BeanDefinition,并检查该对象类类型,比如不能是抽象类等。 3.5 根据 beanName获取所有该 bean依赖的 Bean集合,如果该集合有值,则遍历DI(递归调用 getBean())该 bean集合里的bean,并把bean注册给当前的bean(维护了一个 map来存放关系)。 3.6 如果3.4中获取的 BeanDefinition是单例,则根据该单例对象和 beanName和 args创建一个实例对象;否则,判断 BeanDefinition是否是原型,如果是则根据 beanName,该对象, args创建一个实例;否则拿到3.4获取的 BeanDefinition对象的生命周期 Scope,然后根据 scope来创建实例对象,参数 (beanName,bd,args)。 ​

我们看其中的getMergedLocalBeanDefinition方法和createBean方法,先看前者

Spring中的DI的实现原理_单例模式_03

Spring中的DI的实现原理_实例化_04

可以看到就是通过beanName去我们上一篇说的map容器中查找相应的类,然后包装成一个RootBeanDefinition对象

再回过头看createBean方法

Spring中的DI的实现原理_单例模式_05

Spring中的DI的实现原理_spring中di的实现原理_06

我们看doCreateBean方法,由于截图太长,所以这里放代码

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {

// Instantiate the bean.
//封装被创建的Bean对象(不是真正的Bean)
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//创建实例对象
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
//获取实例化对象的类型
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}

// Allow post-processors to modify the merged bean definition.
//调用PostProcessor后置处理
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}

// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
//向容器中缓存单例模式的Bean对象,以防循环引用
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//为了防止循环引用,尽早持有对象的引用
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

// Initialize the bean instance.
// Bean对象的初始化,依赖注入在此触发
// 这个exposedObject在初始化完成之后返回依赖注入完成后的Bean
Object exposedObject = bean;
try {
//给对象属性赋值,将Bean实例对象封装,并且Bean定义中配置的属性值赋值给实例对象
populateBean(beanName, mbd, instanceWrapper);
//初始化Bean对象
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}

if (earlySingletonExposure) {
//获取指定名称的已注册的单例模式Bean对象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
//根据名称获取已注册的Bean和正在实例化的Bean是同一个
if (exposedObject == bean) {
//当前实例化的Bean初始化完成
exposedObject = earlySingletonReference;
}
//当前Bean依赖其他Bean,并且当发生循环引用时不允许新创建实例对象
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
//获取当前Bean所依赖的其他Bean
for (String dependentBean : dependentBeans) {
//对依赖Bean进行类型检查
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}

// Register bean as disposable.
//注册完成依赖注入的Bean
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}

return exposedObject;
}

我们只需要记住其中的两个地方,一个是instanceWrapper = createBeanInstance(beanName, mbd, args);,另一个是populateBean(beanName, mbd, instanceWrapper);其中前者是根据我们前面封装的RootBeanDefinition对象里面的class实例化出一个代理对象,但是这个对象里面的属性是没有赋值的,而上诉populateBean方法就是用来给这个对象的属性赋值。这两个方法执行完毕,一个代理对象就被完整的构建出来了。我们看createBeanInstance方法。

Spring中的DI的实现原理_spring中di的实现原理_07

Spring中的DI的实现原理_单例模式_08

Spring中的DI的实现原理_sed_09

这里会判断要打造这个代理类对象,是使用JDK的反射还是使用CGLIB来生成,到此,基本上主线流程就已经执行完毕了。

总结

总结下来DI大概是这样的,根据我们要获取的BeanName,去IOC容器中找到对应的class,然后实例化出一个代理类对象,然后给这个对象的属性赋值。

要看详细版的可以看​​彻底搞懂依赖注入(一)Bean实例创建过程​​,写的比我详细很多。