Spring源码深度解析(郝佳)-学习-循环依赖-(构造器-setter)源码分析

20 篇文章 1 订阅
18 篇文章 0 订阅

循环依赖分为构造器循环依赖,以及 setter 循环依赖。下面我们来举例两种循环依赖的具体实例,再来分析源码 。

1.构造器循环依赖

        表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出 BeanCurrentlyIn-CreationException 异常表示循环依赖。
        如在创建 TestA类时,构造器需要 TestB类,那将去创建 TestB ,在创建 TestB类时又发现需要 TestC 类,则又去创建 TestC,最终在创建 TestC时发现又需要 TestA,从而形成一个环,没有办法创建。
        Spring容器将每一个正在创建的 bean 标识符放在一个当前创建 bean 池中,bean 标识符在创建过程中将一直保存在这个池中,因此,如果在创建 bean 的过程中发现自己己经在当前创建的 bean 池里时,将抛出 beanCurrentlyInCreationException 异常表示循环依赖,而对于创建完毕的 bean 将从"当前的 bean 池" 中清除掉。
        通过创建一个测试来分析具体的问题。

TestA.java

public class TestA {
    private TestB testB;
    public TestA() {
    }
    public TestA(TestB testB) {
        this.testB = testB;
    }
    public TestB getTestB() {
        return testB;
    }
    public void setTestB(TestB testB) {
        this.testB = testB;
    }
}

TestB.java

public class TestB {
    private TestC testC;
    public TestB() {
    }
    public TestB(TestC testC) {
        this.testC = testC;
    }
    public TestC getTestC() {
        return testC;
    }
    public void setTestC(TestC testC) {
        this.testC = testC;
    }
}

TestC.java

public class TestC {
    private TestA testA;
    public TestC() {
    }
    public TestC(TestA testA) {
        this.testA = testA;
    }
    public TestA getTestA() {
        return testA;
    }
    public void setTestA(TestA testA) {
        this.testA = testA;
    }
}

spring37_2.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="testA" class="com.spring_1_100.test_31_40.test37.TestA">
        <constructor-arg ref="testB"></constructor-arg>
    </bean>
    
    <bean id="testB" class="com.spring_1_100.test_31_40.test37.TestB">
        <constructor-arg ref="testC"></constructor-arg>
    </bean>

    <bean id="testC" class="com.spring_1_100.test_31_40.test37.TestC">
        <constructor-arg ref="testA"></constructor-arg>
    </bean>
</beans>

测试

@Test
public void test1() {
    ApplicationContext bf = new ClassPathXmlApplicationContext("classpath:spring_1_100/config_31_40/spring37_2.xml");
    System.out.println(((TestA) bf.getBean("testA")).getTestB().getTestC().getTestA());
}

结果抛出异常
在这里插入图片描述

2.setter 注入实例

spring37.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="testA" class="com.spring_1_100.test_31_40.test37.TestA">
        <property name="testB" ref="testB"></property>
    </bean>

    <bean id="testB" class="com.spring_1_100.test_31_40.test37.TestB">
        <property name="testC" ref="testC"></property>
    </bean>

    <bean id="testC" class="com.spring_1_100.test_31_40.test37.TestC">
        <property name="testA" ref="testA"></property>
    </bean>

</beans>

测试

@Test
public void test2() {
    ApplicationContext bf = new ClassPathXmlApplicationContext("classpath:spring_1_100/config_31_40/spring37.xml");
    System.out.println(((TestA) bf.getBean("testA")).getTestB().getTestC().getTestA());
}

结果输出
在这里插入图片描述

下面我们来分析源码

BeanDefinitionParserDelegate.java

/**
 * Get the value of a property element. May be a list etc.
 * Also used for constructor arguments, "propertyName" being null in this case.
 * 解析获取<property>元素的值
 * 通过下面的源码解析,我们了解了Spring配置文件中的<bean>元素中的<property>子元素的相关配置,
 * 1.ref 被封装成指向依赖对象的一个引用
 * 2.value 被封装成一个字符串类型的对象
 * 3.ref 和value都是通过解析数据类型属性值.setSource(extractSource(ele));将方法的属性或者引用与引用属性关系起来
 * 最后<property>元素的子元素通过parsePropertySubElement()方法解析,下面我们继续分析该方法的源码,了解其解析过程
 *
 * 从代码上来看,对函数的属性元素的解析,经历了以下的几个过程
 * 1.略过description或者meta
 * 2.提取constructor-arg上的ref和value属性,以便于根据规则验证正确性,其规则为在constructor-arg 上不存在以下的情况
 * 同时既有ref又有value属性
 * 存在ref属性或者value属性且又有子元素
 * 3.ref属性的处理,使用RunTimeBeanReference封装对应的ref名称,如:
 * <constructor-arg ref="a">
 *
 * </constructor-arg>
 * 4.value属性的处理,使用TypeStringValue封装,如:
 * <constructor-arg value="a"></constructor-arg>
 * 5.子元素的处理
 * <constructor-arg >
 *      <map>
 *          <entry key="key" value="value"></entry>
 *      </map>
 * </constructor-arg>
 * 而对于子元素的处理,例如,这里反映到的在构造函数中嵌入了子元素map是怎样实现的呢?parsePropertySubElement中对实现了对各种子元素的处理
 */
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
    String elementName = (propertyName != null) ?
            "<property> element for property '" + propertyName + "'" :
            "<constructor-arg> element";
    // 获取<property>中的所有的子元素,只能是ref,value,list,etc中的一种类型
    // Should only have one child element: ref, value, list, etc.
    NodeList nl = ele.getChildNodes();
    Element subElement = null;
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        // 子元素是description和meta属性 不做处理
        if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
                !nodeNameEquals(node, META_ELEMENT)) {
            // Child element is what we're looking for.
            if (subElement != null) {
                error(elementName + " must not contain more than one sub-element", ele);
            } else {
                // 当property元素包含子元素
                subElement = (Element) node;
            }
        }
    }
    // 解析constructor-arg 的ref 属性
    boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
    // 解析constructor-arg 上的value属性
    boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
    // 判断属性值是ref还是value,不允许既是ref 又是value
    if ((hasRefAttribute && hasValueAttribute) ||
            ((hasRefAttribute || hasValueAttribute) && subElement != null)) {
        /**
         * 在constructor-arg上不存在:
         * 1.同时既有ref属性又有value属性
         * 2.存在ref属性或者value属性且又有子元素
         */
        error(elementName +
                " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
    }
    // 如果属性值是ref ,创建一个ref 的数据对象,RuntimeBeanReference,这个对象封装了ref
    if (hasRefAttribute) {
        String refName = ele.getAttribute(REF_ATTRIBUTE);
        if (!StringUtils.hasText(refName)) {

            error(elementName + " contains empty 'ref' attribute", ele);
        }
        //ref属性的处理,使用RuntimeBeanReference封装对应的ref名称
        RuntimeBeanReference ref = new RuntimeBeanReference(refName);
        ref.setSource(extractSource(ele));
        return ref;
        // 如果属性值是value,创建一个value数据对象,typedStringValue,这个对象封装了value
    } else if (hasValueAttribute) {
        // 一个持有String类型的对象
        TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
        // 设置这个value的数据对象被当前对象所引用
        valueHolder.setSource(extractSource(ele));
        return valueHolder;
    } else if (subElement != null) {
        // 解析<property>子元素
        return parsePropertySubElement(subElement, bd);
    } else {
        // 属性值既不是ref也不是value,解析出错,返回null
        // Neither child element nor "ref" or "value" attribute found.
        error(elementName + " must specify a ref or value", ele);
        return null;
    }
}

最终将运行时的值以RuntimeBeanReference形式保存到BeanDefinition的genericArgumentValues中。

我们在学习源码之前,我们了解一下 bean 的创建过程中的几个概念。

  • singletonObjects : 用于保存 BeanName 和创建 bean实例之间的关系,bean name -> bean instance
  • singletonFactories : 用于保存 beanName 和创建 bean 工厂之间的关系,bean name --> object Factory
  • earlySingletonObjects : 也是保存 BeanName 和创建 bean 实例之间的关系,与 singletonObjects 的不同之处在于,当一个单例 bean被放置在里面的时候,那么当 bean 还在创建过程中,就可以通过 getBean 方法获取到了,其上的是用来检测循环引用。
  • registeredSingletons : 用来保存当前已经注册的 bean
  • earlySingletonExposure: 从字面的意思是理解提早曝光单例,我们暂不定义它的学名是什么,我们感兴趣的是哪些条件影响这个值
  • this.allowCircularReferences:是不允许循环依赖,很抱歉,并没有找到配置文件中如何配置的,但是在 AbstractRefreshableApplicationContext 中提供了设置函数,可以通过硬编码的方式工进行设置或者可以通过自定义命名空间进行配置,其中硬编码的代码如下
            ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext(“apsectTest.xml”);
            bf.setAllBeanDefinitionOverrideing(false);
  • mbd.isSingleton():没有太多的可以理解,此 RootBeanDefinition 代表的是否是单例
  • isSingletonCurrentlyInCreation(beanName) ;该 bean 是不是创建中,在 Spring 中会有个专门的属性默认为 DefaultSingletonBeanRegistry 的singletonsCurrentlyInCreation 来记录 bean 的加载状态,在 bean 开始创建前会将 beanName 记录在属性中,在 bean 的创建结束后 将 beanName 从属性中移除,那么我们跟随代码一路起来可是对这个属性的记录并没有多少印象,这个状态是哪里记录的呢?不同的 scope 的记录不一样我们以 singleton 为例
    bean 创建之前加入到singletonsCurrentlyInCreation中。
	protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

        bean创建之后移除singletonsCurrentlyInCreation。

	protected void afterSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
			throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
		}
	}

        加入到 bean 中

	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			//singletonObjects是一个ConcurrentHashMap
			//用来缓存单例对象
			this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
			//singletonFactories是一个HashMap
			//里面缓存着单例工厂
			this.singletonFactories.remove(beanName);
			//早期单例对象
			//earlySingletonObjects是一个HashMap
			this.earlySingletonObjects.remove(beanName);
			//registeredSingletons是一个LinkedHashSet
			//被注册单例的集合,以注册的顺序包含着bean name
			this.registeredSingletons.add(beanName);
		}
	}

AbstractAutowireCapableBeanFactory.java

/**
 * 真正创建Bean的方法
 * 通过下面的源码注释可以看到,具体的人依赖注入的实现其实就是在下面两个方法中
 * 1.createBeanInstance()方法,生成Bean所包含的java对象实例
 * 2.populateBean()方法,对Bean的属性依赖注入进行处理
 * 下面继续分析这两个方法代码实现,那么这个方法到底是干什么用的呢?
 * 其实是在 Spring 中确实没有 override-method 这样的配置,但是如果读过前面的部分,可能会发现,在 Spring 配置中存在 lookup-method
 * 和 replace-method 的,而这两个配置加载其实就是将配置统一存放在 BeanDefinition 中的 methodOverrides 属性里,而这个函数的操作
 * 其实也是对针对这两个配置的
 * 3. 应用初始化前后处理器,解析指定的 bean 是否存在初始化前的短路操作
 * 4.创建 bean
 * 我们首先查看下 override 属性标记及验证的逻辑实现
 *
 *  介绍了循环依赖及 Spring 中的循环依赖的处理方式后,我们继续4.5小节的内容,当经过 resolveBeforeInstantiation 方法后,程序有两个
 *  选择,如果创建了代理或者说重写了 InstantiationAwareBeanPostProcessor 的 PostProcessBeforeInstantiation 方法并在方法的
 *  postProcessBeforeInstantiation 中改变了 bean ,则直接返回就可以了,否则需要进行常规的 bean 的创建,而这个常规的 bean 的创建
 *  就是在 docreateBean 中完成了
 * 
 * 这个代码不是很复杂,但是很多的人不是太理解这段代码的作用,而且,这个代码从些函数中去理解 ,也很难弄懂其中的含义,我们需要从全局的角度
 * 去思考 Spring 依赖解析的办法
 */
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
	// 封装被创建物Bean对象
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
		// 根据指定的 bean 使用对应的策略创建新的实例,如 : 工厂方法,构造函数,自动注入,简单的初始化
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
	// 获取实例化Bean对象的类型
	Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

	// 调用PostProcessor 后置处理器
	synchronized (mbd.postProcessingLock) {
		if (!mbd.postProcessed) {
			// 应用 MergedBeanDefinitionPostProcessor
			// bean的合并处理,Autowired注解正是通过此方法实现诸如类型的预解析
			applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			mbd.postProcessed = true;
		}
	}
	// 向容器中缓存单例模式的Bean对象,以防止循环使用
	// 是否需要提早曝光,单例& 允许循环依赖&  当前 bean 正在创建中,检测循环依赖
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		if (logger.isDebugEnabled()) {
			logger.debug("Eagerly caching bean '" + beanName +
					"' to allow for resolving potential circular references");
		}
		// 这里是一个匿名的内部类,为了防止循环引用,尽早的有对象引用
		// 为了避免后期的循环依赖,可以在 bean 的初始化完成前将创建的实例 BeanFactory 加入到工厂中
		addSingletonFactory(beanName, new ObjectFactory<Object>() {
			@Override
			public Object getObject() throws BeansException {
				// 对 bean 再一次依赖引用,主要应用 SmartInstantiationAwareBeanPostProcessor ,
				// 其中我们熟知的 AOP 就是这里将 advice 动态织入bean 中,若没有则直接返回 bean ,不做任何处理
				return getEarlyBeanReference(beanName, mbd, bean);
			}
		});
	}

	// Bean对象的初始化,依赖注入在些触发
	// 这个exposedObject对象在初始化完成之后返回依赖注入完成后的Bean
	Object exposedObject = bean;
	try {
		// 将Bean实例对象封装,并且将Bean定义占的配置属性值赋给实例对象,对bean属性进行依赖注入
		// Bean实例对象的依赖注入完成后,开始对Bean实例对象进行初始化,为Bean实例对象应用BeanPostProcessor后置处理器
		// 对 bean 进行填充,将各个属性值注入,其中可能存在依赖于其他的 bean 的属性,则会递归的初始依赖 bean
		// 为什么构造器注入的时候会出现循环依赖问题而属性注入不会出现循环依赖问题?
		// 在使用构造器注入时,会在此处产生递归操作,在第四层创建A时DefaultSingletonBeanRegistry的beforeSingletonCreation方法中会报错
		// 因为DefaultSingletonBeanRegistry的this.singletonFactories中没有A的bean缓存。所以在beforeSingletonCreation中便会报错。
		// 那么为什么用属性注入时就不会报错呢?因为this.singletonFactories缓存发生在当前方法的addSingletonFactory行,而属性注入的递归发生在
		// 这一行,也就是说 先进行了缓存。而构造器注入时 还没来得及缓存就已经递归到下一层了。
		// 属性填充
		populateBean(beanName, mbd, instanceWrapper);
		if (exposedObject != null) {
			// 调用初始化方法,比如 init-method
			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) {
		// earlySingletonReference 只有检测到你有循环依赖的情况下才会不为空
		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<String>(dependentBeans.length);
				// 获取当前的Bean所依赖的其他的Bean
				for (String dependentBean : dependentBeans) {
					// 对依赖的Bean进行类型检查 
					if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
						actualDependentBeans.add(dependentBean);
					}
				}
				/**
				 * 因为 bean 创建后其所依赖的 bean 一定是已经被创建了的
				 * actualDependentBeans 不为空则表示当前的 bean 创建后其依赖的 bean 却没有全部的创建完,也就是说存在循环依赖
				 */
				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.");
				}
			}
		}
	}

	try {
		// 根据 scope 注册 bean
		registerDisposableBeanIfNecessary(beanName, bean, mbd);
	}
	catch (BeanDefinitionValidationException ex) {
		throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
	}
	return exposedObject;
}

尽管日志与异常的内容非常的重要,但是在阅读源码的时候似乎大部分的人都会直接忽略掉,请读者在阅读源码时,多多关注。

  • 1.如果是单例,则需要首先清除缓存
  • 2.实例化 bean ,将 beanDefinition 转换成 BeanWrapper
  • 3.转换是一个复杂的过程,但是我们可以尝试要搬大致的功能,如下所示
            如果存在工厂方法,则使用工厂方法进行初始化
    一个类有多个构造函数,每个构造函数都有不同的参数,所需要的根据参数锁定构造函数并进行初始化如果既不存在工厂方法也不存在带有参数的构造方法,则使用默认构造函数进行 bean 的实例化, MergedBeanDefinitionPostProcessor 的应用,bean 的合并后处理,Autowired 注解正是通过此方法实现诸如类型的预解析
  • 4.依赖处理
            在 Spring 中会有循环依赖的情况,例如: 当 A 中含有 Bean 的属性, 而 B 中又含有 A的属性时就构成一个循环依赖,此时如果 A 和 B
    都是单例,那么在 Spring 中处理方式就是当创建 B 的时候,涉及自动注入 A 的步骤时,并不是直接去再次创建 A ,而是通过放入到缓存中的
    ObjectFactory 来创建实例,这样就解决了循环依赖的问题
  • 5.属性填充
            将所有的属性填充至 bean 的实例中
  • 6.循环依赖的各种检查
            之前反映到过,在 Spring 中要解析的循环依赖只是对单例有效,而对于 prototype 的 bean ,Spring 没有好的解决办法,唯一要做的就是抛出
    异常,在这个步骤里面会检测已经加载的 bean 是否已经出现了依赖循环,并判断是否需要抛出异常
  • 7.注册 DisposableBean
            如果配置了 destory-method , 这里需要注册以便于在销毁时候调用
  • 8.完成创建并返回

AbstractAutowireCapableBeanFactory.java

/**
 * 在CreateBeanInstance()方法中,根据指定的初始化策略,使用了简单的工厂,工厂方法或者容器的自动装配生成java实例对象,创建对象的代码如下
 * 创建Bean的实例对象
 */
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
	// 确认Bean是可实例化的
	Class<?> beanClass = resolveBeanClass(mbd, beanName);
	// 使用工厂方法对Bean进行实例化,
	//  getModifiers  得到的就是 前面的 的修饰符 ,这个方法 字段和方法 都有。这个方法的值是 修饰符 相加的到的值。
	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());
	}
	// 如果工厂方法不不为空,则使用工厂方法初始化策略
	if (mbd.getFactoryMethodName() != null)  {
		// 调用工厂方法进行实例化
		return instantiateUsingFactoryMethod(beanName, mbd, args);
	}
	// 使用容器的自动装配方法进行实例化
	boolean resolved = false;
	boolean autowireNecessary = false;
	if (args == null) {
		synchronized (mbd.constructorArgumentLock) {
			// 一个类有多个构造函数都有不同的参数,所以调用需要根据参数锁定构造函数或者对应的工厂方法
			// 所以调用前需要先根据参数锁定构造函数或者工厂方法
			if (mbd.resolvedConstructorOrFactoryMethod != null) {
				resolved = true;
				autowireNecessary = mbd.constructorArgumentsResolved;
			}
		}
	}
	//  如果已经解析过,则使用解析好的构造函数方法不需要再次锁定
	if (resolved) {
		if (autowireNecessary) {
			//配置了自动装配属性,使用了容器的自动装配进行实例化
			//容器的自动装配根据参数的类型匹配Bean的构造方法
			return autowireConstructor(beanName, mbd, null, null);
		}
		else {
			// 使用了默认无参构造方法进行实例化
			return instantiateBean(beanName, mbd);
		}
	}

	// 使用了Bean的构造方法进行实例化
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	if (ctors != null ||
			mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
			mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
		// 带参数实例化,带有参数实例化的过程相当的复杂,因为存在不确定性。
		return autowireConstructor(beanName, mbd, ctors, args);
	}

	// 使用了默认的无参的构造方法进行实例化
	return instantiateBean(beanName, mbd);
}

虽然代码中实例化的细节非常的复杂,但是存在 createBeanInstance 方法中我人还是可以清晰的看到实例化的逻辑

  • 1.如果在 如果 RootBeanDefinition 中存在 facotryMethodName 属性,或者说在配置文件中配置了 factory-method,那么 Spring会尝试使用 instantiateusingFactoryMethod(beanName,mbd,args) 方法根据 RootBeanDefinition 中的配置生成 bean 的实例
  • 2.解析构造函数并在构造函数的实例化,因为一个 bean 对应的类中可能会有多个构造函数,而每个构造函数的参数不同,Spring 在根据参数及类型去判断最终会使用哪个

AbstractAutowireCapableBeanFactory.java

protected BeanWrapper autowireConstructor(
		String beanName, RootBeanDefinition mbd, Constructor<?>[] ctors, Object[] explicitArgs) {

	return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}

ConstructorResolver.java

/**
 * 对于实例的创建 Spring 中分成两种情况,一种是通用的实例化,另一种是带有参数的实例化,带有的实例化过程相当的复杂,因为存在着不确定性
 * ,所以在判断对应的参数做了大量的工作
 *  逻辑很复杂,函数代码量很大,不知道你是否坚持读完了整个函数并理解了整个功能呢? 这里要先吐个,笔者觉得这个函数的写法完全不符合
 *  Spring 的一的风格,如果你一直跟笔者分析思路到这里,相信你或多或少对 Spring 的编码风格有所了解,Spring 的一的做法就是将复杂的
 *  逻辑分解,分成 N 个小函数的嵌套,每一层都是对下一层的逻辑的总结要概要,这样使得每一层的逻辑会变得简单容易理解,在上面的函数中,包含了
 *  很多的逻辑实现,笔者觉得至少应该将逻辑封装在不同的函数而使得在 autowireConstructor 中的逻辑清晰明了
 */
public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefinition mbd,
		Constructor<?>[] chosenCtors, final Object[] explicitArgs) {

	BeanWrapperImpl bw = new BeanWrapperImpl();

	this.beanFactory.initBeanWrapper(bw);

	Constructor<?> constructorToUse = null;
	ArgumentsHolder argsHolderToUse = null;
	Object[] argsToUse = null;
	// explicitArgs 通过 getBean 方法传入
	// 如果 getBean 方法调用的时候指定方法参数那么直接使用
	if (explicitArgs != null) {
		argsToUse = explicitArgs;
	}
	else {
		// 如果在 getBean 方法时候没有指定则尝试从配置文件中解析
		Object[] argsToResolve = null;
		// 尝试从缓存中获取
		synchronized (mbd.constructorArgumentLock) {
			constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
			if (constructorToUse != null && mbd.constructorArgumentsResolved) {
				// 从缓存中取
				argsToUse = mbd.resolvedConstructorArguments;
				if (argsToUse == null) {
					// 配置的构造函数参数
					argsToResolve = mbd.preparedConstructorArguments;
				}
			}
		}
		// 如果缓存中存在
		if (argsToResolve != null) {
			// 解析参数类型,如果给定方法的构造函数 A(int ,int ) 则通过此方法后就会把配置中的("1","1") 转换成(1,1)
			argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
		}
	}

	if (constructorToUse == null) {
		boolean autowiring = (chosenCtors != null ||
				mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		ConstructorArgumentValues resolvedValues = null;

		int minNrOfArgs;
		if (explicitArgs != null) {
			minNrOfArgs = explicitArgs.length;
		}
		else {
			// 提取配置文件中配置构造函数参数
			ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
			// 用于承载解析后的构造函数的参数值
			resolvedValues = new ConstructorArgumentValues();
			// 能解析到这个参数的个数
			minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
		}

		Constructor<?>[] candidates = chosenCtors;
		if (candidates == null) {
			Class<?> beanClass = mbd.getBeanClass();
			try {
				candidates = (mbd.isNonPublicAccessAllowed() ?
						beanClass.getDeclaredConstructors() : beanClass.getConstructors());
			}
			catch (Throwable ex) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Resolution of declared constructors on bean Class [" + beanClass.getName() +
								"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
			}
		}
		// 排序给定的构造函数,首先public 排前面,非 public 排后,其次参数个数降序
		AutowireUtils.sortConstructors(candidates);
		int minTypeDiffWeight = Integer.MAX_VALUE;
		Set<Constructor<?>> ambiguousConstructors = null;
		LinkedList<UnsatisfiedDependencyException> causes = null;

		for (int i = 0; i < candidates.length; i++) {
			Constructor<?> candidate = candidates[i];
			Class<?>[] paramTypes = candidate.getParameterTypes();

			if (constructorToUse != null && argsToUse.length > paramTypes.length) {
				// 如果已经找到选用的构造函数或者需要的参数个数小于当前的构造函数个数的终止,因此 已经按照参数个数降序排序
				break;
			}
			if (paramTypes.length < minNrOfArgs) {
				// 参数个数不相等
				continue;
			}

			ArgumentsHolder argsHolder;
			if (resolvedValues != null) {
				try {
					// 有参数则根据值构造对应的参数类型的参数
					// 注释上获取参数的名称
					String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
					if (paramNames == null) {
						ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
						if (pnd != null) {
							// 获取指定构造函数的参数名称
							paramNames = pnd.getParameterNames(candidate);
						}
					}
					// 根据名称和数据类型创建参数持有者
					argsHolder = createArgumentArray(
							beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);
				}
				catch (UnsatisfiedDependencyException ex) {
					if (this.beanFactory.logger.isTraceEnabled()) {
						this.beanFactory.logger.trace(
								"Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
					}
					if (causes == null) {
						causes = new LinkedList<UnsatisfiedDependencyException>();
					}
					causes.add(ex);
					continue;
				}
			}
			else {
				// 构造函数没有参数的情况
				if (paramTypes.length != explicitArgs.length) {
					continue;
				}
				// 构造函数没有参数的情况
				argsHolder = new ArgumentsHolder(explicitArgs);
			}
			// 探测是否有不确定性构造函数存在,例如不同的构造函数的参数为父子关系
			int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
					argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
			// 如果它代表着当前最接近匹配则选择作为构造函数
			if (typeDiffWeight < minTypeDiffWeight) {
				constructorToUse = candidate;

				argsHolderToUse = argsHolder;
				argsToUse = argsHolder.arguments;
				minTypeDiffWeight = typeDiffWeight;
				ambiguousConstructors = null;
			}
			else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
				if (ambiguousConstructors == null) {
					ambiguousConstructors = new LinkedHashSet<Constructor<?>>();
					ambiguousConstructors.add(constructorToUse);
				}
				ambiguousConstructors.add(candidate);
			}
		}

		if (constructorToUse == null) {
			if (causes != null) {
				UnsatisfiedDependencyException ex = causes.removeLast();
				for (Exception cause : causes) {
					this.beanFactory.onSuppressedException(cause);
				}
				throw ex;
			}
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Could not resolve matching constructor " +
					"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
		}
		else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Ambiguous constructor matches found in bean '" + beanName + "' " +
					"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
					ambiguousConstructors);
		}

		if (explicitArgs == null) {
			// 将解析的构造函数加入到缓存中
			argsHolderToUse.storeCache(mbd, constructorToUse);
		}
	}

	try {
		Object beanInstance;

		if (System.getSecurityManager() != null) {
			final Constructor<?> ctorToUse = constructorToUse;
			final Object[] argumentsToUse = argsToUse;
			beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
				@Override
				public Object run() {
					return beanFactory.getInstantiationStrategy().instantiate(
							mbd, beanName, beanFactory, ctorToUse, argumentsToUse);
				}
			}, beanFactory.getAccessControlContext());
		}
		else {
			beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
					mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
		}
		// 将构建的实例加入到 BeanWapper 中
		bw.setWrappedInstance(beanInstance);
		return bw;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(mbd.getResourceDescription(), beanName,
				"Bean instantiation via constructor failed", ex);
	}
}

我们总览一下整个函数,其实现在功能考虑以下的几个方面

  • 1.构造函数参数的确定

            根据 explicitArgs 参数判断,如果传入的参数 explicitArgs 不为空,那边可以直接确定参数,因为 explicitArgs 参数在调用 Bean 的时候用户指定的,在 BeanFactory类中存在这样的方法
             Object getBean(String name,Object …args ) throws BeansException;
    在获取 bean 的时候,用户不但可以指定 bean 的名称还可以指定的 bean 所对应的类的构造函数或者工厂方法的参数,主要用于静态工厂方法的调用,而这里需要给定完全匹配的参数,所以,便可以判断,如果传入的参数explicitArgs 不为空,而可以确定构造函数参数就是它了。 缓存中获取除此之外 ,确定参数的办法如果之前已经分析过了,也就是说构造函数的参数已经记录在缓存中,那么便可以直接拿来使用,而且,这里要提到是,在缓存中可能是参数的最终类型也可能是参数的初始化类型,例如,构造函数参数要求的是 int 类型,但是原始参数可能是 String 类型,那么即使在缓存中得到了参数,也需要经过类型转换器的过滤以确保参数类 与对应的构造函数完全对应配置文件的获取,如果不能根据传入的参数 explicitArgs 确定构造函数参数也无法在缓存中得到相关的信息,那么只能开始新一轮的分析了分析获取配置文件中配置的构造函数信息开始,经过之前的分析,我们知道,Spring 中配置文件中的信息经过转换都会通过 BeanDefinition实例承载,也就是参数的 mdb 中包含,那么可以通过调用 mbd.getConstructorArgmentValues()中来获取配置的构造函数信息,有了配置中的信息就可以获取对应的参数信息,获取参数的信息包括直接指定值,如:直接指定构造函数中的某个值为原始类型的 String 类型,或者是其对其他的 bean 的引用,而这一处理委托给 resolveContructorArguments 方法,并返回能解析到的参数的个数

  • 2.构造函数的确定
            经过第一步后已经确定构造函数的参数,接下来的任务就是根据构造函数的参数锁定的对应的构造函数,而匹配的方法就是根据参数的匹配,所以在这个匹配之前需要先对构造函数按照 public,protected,private构造函数修饰符,参数个数 降序,迅速判断排在后面的构造函数参数的个数是否符合条件
    由于配置文件中并不是唯一限制使用参数的位置索引的方式去创建,同样还支持指定参数名称进行设定参数的情况,如<constructor-arg name=“aa”>,这种情况下就需要首先确定的构造函数的参数名称:
    获取参数的名称可以有两种方式
            1.通过注解的方式来获取。
            2.使用 Spring 中提供的工具类 ParameterNameDiscoverer 来获取

            构造函数,参数名称,参数类型,参数值都确定后就可以锁定构造函数以及转换对应的参数类型了

  • 3.根据确定的构造函数转换对应的参数类型
    主要是使用 Spring中提供的类型转换器或者用户提供的自定义类型转换器进行转换

  • 4.构造函数不确定性的验证

    当然,有时候即使构造函数,参数名称,参数类型,参数值确定后也不一定直接锁定构造函数,不同的构造函数的参数为父子关系,所以 Spring 在最后双做了一次验证

  • 5.根据实例化策略以及得到的构造函数及构造函数参数实例化 Bean

ConstructorResolver.java

/**
 * Resolve the constructor arguments for this bean into the resolvedValues object.
 * This may involve looking up other beans.
 * <p>This method is also used for handling invocations of static factory methods.
 */
private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
		ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {

	TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
			this.beanFactory.getCustomTypeConverter() : bw);
	BeanDefinitionValueResolver valueResolver =
			new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);

	int minNrOfArgs = cargs.getArgumentCount();

	for (Map.Entry<Integer, ConstructorArgumentValues.ValueHolder> entry : cargs.getIndexedArgumentValues().entrySet()) {
		int index = entry.getKey();
		if (index < 0) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Invalid constructor argument index: " + index);
		}
		if (index > minNrOfArgs) {
			minNrOfArgs = index + 1;
		}
		ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue();
		if (valueHolder.isConverted()) {
			resolvedValues.addIndexedArgumentValue(index, valueHolder);
		}
		else {
			Object resolvedValue =
					valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
			ConstructorArgumentValues.ValueHolder resolvedValueHolder =
					new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
			resolvedValueHolder.setSource(valueHolder);
			resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);
		}
	}
}

BeanDefinitionValueResolver.java


/**
 *	容器对属性进行依赖注入时,如果发现属性需要进行类型转换,例如属性值是容器中另一个Bean实例对象的引用,则容器首先需要根据属性值
 *进行解析出所引用的对象,然后,才能将该引用的对象注入到目标实例的属性上,对属性的解析由resolveValueIfNecessary()方法的实现,其源码
 * 如下
 * 		解析属性值,对注入类型的进行转换
 * 通过下面的代码分析,我们明白了Spring 是如何通过引用类型,内部类及集合类型的属性进行分析的,解析完成之后,就可以进行依赖注入了
 * ,依赖注入的过程就是将Bean对象实例设置到它们所依赖的Bean的属性上,真正的依赖注入是通过bw.setPropertyValues()方法实现的,
 * 该方法也使用了委派模式,在BeanWrapper接口中定义了方法声明,依赖注入的具体的实现交由其实现类BeanWrapperImpl完成的,
 * 下面我们根据BeanWrappperImpl类中依赖注入相关的代码来完成
 */
public Object resolveValueIfNecessary(Object argName, Object value) {
	// 对引用类型的属性值进行解析
	if (value instanceof RuntimeBeanReference) {
		RuntimeBeanReference ref = (RuntimeBeanReference) value;
		// 调用引用类型属性的解析方法
		return resolveReference(argName, ref);
	}
	// 对引用容器中的另一个Bean名称属性进行解析
	else if (value instanceof RuntimeBeanNameReference) {
		String refName = ((RuntimeBeanNameReference) value).getBeanName();
		refName = String.valueOf(doEvaluate(refName));
		// 从容器中获取指定名称的Bean
		if (!this.beanFactory.containsBean(refName)) {
			throw new BeanDefinitionStoreException(
					"Invalid bean name '" + refName + "' in bean reference for " + argName);
		}
		return refName;
	}
	// 对Bean的类型的属性进行解析,主要是指Bean的内部类
	else if (value instanceof BeanDefinitionHolder) {
		BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
		return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
	}

	else if (value instanceof BeanDefinition) {
		BeanDefinition bd = (BeanDefinition) value;
		String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
				ObjectUtils.getIdentityHexString(bd);
		return resolveInnerBean(argName, innerBeanName, bd);
	}
	// 对集合数组类型的属性进行解析
	else if (value instanceof ManagedArray) {
		ManagedArray array = (ManagedArray) value;
		// 获取数组的类型
		Class<?> elementType = array.resolvedElementType;
		if (elementType == null) {
			String elementTypeName = array.getElementTypeName();
			if (StringUtils.hasText(elementTypeName)) {
				try {
					// 使用反射机制创建指定类型的对象
					elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
					array.resolvedElementType = elementType;
				}
				catch (Throwable ex) {
					throw new BeanCreationException(
							this.beanDefinition.getResourceDescription(), this.beanName,
							"Error resolving array type for " + argName, ex);
				}
			}
			// 没有获取到数组的类型,也没有获取到元素类型
			// 则直接设置数组的类型为Object
			else {
				elementType = Object.class;
			}
		}
		return resolveManagedArray(argName, (List<?>) value, elementType);
	}
	// 解析List类型的属性值
	else if (value instanceof ManagedList) {
		return resolveManagedList(argName, (List<?>) value);
	}
	// 解析set类型的属性值
	else if (value instanceof ManagedSet) {
		return resolveManagedSet(argName, (Set<?>) value);
	}
	// 解析map类型的属性值
	else if (value instanceof ManagedMap) {
		return resolveManagedMap(argName, (Map<?, ?>) value);
	}
	// 解析props类型的属性值,props其实就是key 和value均为字符串的map
	else if (value instanceof ManagedProperties) {
		Properties original = (Properties) value;
		// 创建一个副本,作为解析后的返回值
		Properties copy = new Properties();
		for (Map.Entry<Object, Object> propEntry : original.entrySet()) {
			Object propKey = propEntry.getKey();
			Object propValue = propEntry.getValue();
			if (propKey instanceof TypedStringValue) {
				propKey = evaluate((TypedStringValue) propKey);
			}
			if (propValue instanceof TypedStringValue) {
				propValue = evaluate((TypedStringValue) propValue);
			}
			copy.put(propKey, propValue);
		}
		return copy;
	}
	// 解析字符串类型的属性值
	else if (value instanceof TypedStringValue) {
		TypedStringValue typedStringValue = (TypedStringValue) value;
		Object valueObject = evaluate(typedStringValue);
		try {
			// 获取属性的目标类型
			Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
			if (resolvedTargetType != null) {
				// 对目标类型的属性进行解析,递归调用
				return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
			}
			// 如果没有获取属性的目标对象,则按照Object类型返回
			else {
				return valueObject;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					this.beanDefinition.getResourceDescription(), this.beanName,
					"Error converting typed String value for " + argName, ex);
		}
	}
	else {
		return evaluate(value);
	}
}

BeanDefinitionValueResolver.java

/**
 * 解析引用类型的属性值
 */
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
	try {
		String refName = ref.getBeanName();
		// 获取Bean的名称
		refName = String.valueOf(doEvaluate(refName));
		// 如果引用类型的对象在父容器中,则从父容器中获取指定的引用类型对象
		if (ref.isToParent()) {
			if (this.beanFactory.getParentBeanFactory() == null) {
				throw new BeanCreationException(
						this.beanDefinition.getResourceDescription(), this.beanName,
						"Can't resolve reference to bean '" + refName +
						"' in parent factory: no parent factory available");
			}
			return this.beanFactory.getParentBeanFactory().getBean(refName);
		}
		// 从当前的容器中获取指定的引用Bean对象,如果指定的Bean没有被实例化,
		// 则会递归的触发引用Bean的初始化和依赖注入
		else {
			Object bean = this.beanFactory.getBean(refName);
			// 当前实例化对象依赖引用对象
			this.beanFactory.registerDependentBean(refName, this.beanName);
			return bean;
		}
	}
	catch (BeansException ex) {
		throw new BeanCreationException(
				this.beanDefinition.getResourceDescription(), this.beanName,
				"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
	}
}

AbstractBeanFactory.java

@Override
public Object getBean(String name) throws BeansException {
	// doGetBean才是真正的向Ioc容器中获取管理的Bean
	return doGetBean(name, null, null, false);
}

AbstractBeanFactory.java

@SuppressWarnings("unchecked")
protected <T> T doGetBean(
		final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
		throws BeansException {
	// 根据指定的名称获取被管理的Bean的名称,剥离指定的名称中对容器的相关依赖
	// 如果指定的是别名,将别名转换成规范的Bean的名称
	final String beanName = transformedBeanName(name);
	Object bean;
	// 检查缓存中或者实例工厂中是否有对应的实例
	// 为什么首先会使用这段代码呢?
	// 因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候,为了避免循环依赖
	// Spring 创建 bean 的原则是不等 bean 的创建完成就会将创建的 bean  的 ObjectFactory 提早曝光
	// 也就是将 ObjectBeanFactory  加入到缓存中,一旦下个 bean 创建的时候需要依赖上个 bean 则直接使用 ObjectFactory
	// 直接尝试从缓存中获取或者 singletonFactories 中的 ObjectFactory 中获取
	Object sharedInstance = getSingleton(beanName);
	// 先从缓存 中读取是否已经有被创建过的单例模式的bean
	// 对于单例模式的Bean,整个Ioc容器只创建一次,不需要重复的创建
	if (sharedInstance != null && args == null) {
		if (isSingletonCurrentlyInCreation(beanName)) {
			//如果在容器中已经有指定名称的单例模式的Bean,被创建,直接返回已经创建好的Bean
			logger.info("doGetBean Returning eagerly cached instance of singleton bean '" + beanName +
					"' that is not fully initialized yet - a consequence of a circular reference");
		}else {
			logger.info("doGetBean Returning cached instance of singleton bean '" + beanName + "'");
		}
		// 获取给定的Bean的实例对象,主要完成FactoryBean相关处理
		// 注意:BeanFactory是管理Bean的工厂,FactoryBean是创建对象的工厂Bean,两者之间是有很多的区别的 | 返回对应的实例
		// 有个时候存在诸如 BeanFactory 的情况并不是直接返回实例本身而是返回指定方法返回的实例
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	} else {
		//缓存中已经在有原型模式的Bean
		// 但是由于循环引用导致实例化对象失败
		// 只有在单例的情况下都会以尝试解析循环依赖,原型模式情况下,如果存在 A 中有 B 的属性,B中有 A的属性,那么当依赖
		//  注入的时候,就会产生当 A 还示创建完成的时候因为
		// 对 B 的创建再次返回创建 A ,造成我一依赖,也就是下面的情况
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}

		// 对于Ioc容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否
		// 能在当前的BeanFactory中获取所需要的Bean,如果不能则委托当前的容器
		// 的父容器去查找 ,如果还是找不到,则沿着容器的继承体系向父容器中查找
		BeanFactory parentBeanFactory = getParentBeanFactory();
		//如果 beanDefinitionMap 中也就是在所有的已经加载的类中不包括
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			// 解析指定的Bean名称的原始名称
			String nameToLookup = originalBeanName(name);
			// 递归到 BeanFactory 中查找
			if (args != null) {
				// 委派父容器根据指定名称和显示的参数查找
				return (T) parentBeanFactory.getBean(nameToLookup, args);
			}
			else {
				// 委派父容器根据指定名称和类型查找
				return parentBeanFactory.getBean(nameToLookup, requiredType);
			}
		}
		//如果不是仅仅做类型检查则是创建 bean,这里需要进行记录
		if (!typeCheckOnly) {
			// 向容器标记指定的Bean是否已经被创建
			markBeanAsCreated(beanName);
		}
		try {
			//根据指定的Bean的名称获取其父级别的Bean的定义
			// 主要解决Bean继承子类和父类公共属性的问题,将存在 XML 配置文件的 GenericBeanDefinition 转换为 RootBeanDefinition
			// 如果指定 BeanName 是子的 Bean 的话同时合并父类的相关属性
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);
			// 如果存在依赖则需要递归实例化依赖的 bean
			String[] dependsOn = mbd.getDependsOn();
			//如果当前的Bean有依赖的Bean
			if (dependsOn != null) {
				for (String dependsOnBean : dependsOn) {
					if (isDependent(beanName, dependsOnBean)) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
					}
					//把被依赖的Bean注册给当前的依赖的Bean 
					registerDependentBean(dependsOnBean, beanName);
					// 递归调用getBean()方法,获取当前的Bean的依赖的Bean
					getBean(dependsOnBean);
				}
			}

			// 创建单例模式的Bean的实例对象
			if (mbd.isSingleton()) {
				//这里使用了一个匿名的内部类创建Bean实例对象,并且注册给所依赖的对象
				sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
					@Override
					public Object getObject() throws BeansException {
						try {
							// ObjectFactory核心的部分其实只调用了createBean的方法,所以我们还需要到createBean方法中追寻真理
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// 显示的从容器中单例模式的Bean缓存中清除实例对象
							destroySingleton(beanName);
							throw ex;
						}
					}
				});
				//获取给定的Bean的实例对象
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}
			//Ioc容器创建原型模式的Bean的实例对象
			else if (mbd.isPrototype()) {
				// 原型模式(Prototype)每次都会创建一个新的对象
				Object prototypeInstance = null;
				try {
					//回调BeforePrototypeCreation()方法,默认的功能是在注册当前创建的原型对象
					beforePrototypeCreation(beanName);
					//创建指定的Bean的对象实例
					prototypeInstance = createBean(beanName, mbd, args);
				}
				finally {
					//回调afterPrototypeCreation()方法,默认的功能是告诉Ioc容器不要再创建指定的Bean的原型对象
					afterPrototypeCreation(beanName);
				}
				//获取指定的Bean的实例对象
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			}
			//如果要创建的对象既不是单例模式,也不是原型模式,则根据Bean定义资源中
			// 配置的生命周期范围,选择实例化Bean的合法方法,这种方法在WEb应用程序中
			//比较常用,如request,session,application等生命周期
			else {
				String scopeName = mbd.getScope();
				final Scope scope = this.scopes.get(scopeName);
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
				}
				try {
					// 这里又使用了一个匿名的内部类,获取 一个指定的生命周期的实例
					Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
						@Override
						public Object getObject() throws BeansException {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						}
					});
					// 获取指定的Bean的实例对象
					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;
		}
	}
	// 对创建Bean实例对象进行检查 | 检查需要的类型是否符合 bean 的实际类型
	if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
		try {
			return getTypeConverter().convertIfNecessary(bean, requiredType);
		}
		catch (TypeMismatchException ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Failed to convert bean '" + name + "' to required type [" +
						ClassUtils.getQualifiedName(requiredType) + "]", ex);
			}
			throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
		}
	}
	return (T) bean;
}

真正的实现向Ioc容器获取Bean的功能,也是就触发依赖注入的地方通过对IOC容器的获取Bean的的分析,我们可以看到,在Spring中,如果Bean定义为单例模式(Singleton)的,容器在创建之前先从缓存中查找以确保整个容器中只存在一个实例对象时,如果Bean定义为原型模式,则容器每次都会创建一个新的的实例对象,除此之外,Bean定义还可以指定其生命周期范围上面的源码只定义了根据Bean定义的不同模式采取的创建Bean实例对象的不同策略,具体的Bean实例对象创建过程由实现了ObjectFactory接口匿名内部类createBean()方法完成,ObjectFactory接口使用了委派模式,具体的Bean实例创建过程交由其实现类AbstractAutowireCapableBeanFactory 完成,下面我们继续分析AbstractAutowireCapableBeanFactory的createBean()方法的源码,理解创建Bean实例 具体的过程。

Spring 加载 bean 的过程

  1. 转换对应的 beanName
    或许很多的人不理解转换对应的 beanName 是什么意思,传入的参数 name 就是 beanName 吗?其实不是,这个传入的参数可能是别名,也可能是
    其实不是,这里传入的参数可能是别名,也可能是 FactoryBean,所以需要进行一系列的解析,这些解析的内容包括如下内容去除 FactoryBean 的修饰符,也就是如果 name="&aa" ,那么会首先去除&而使得 name = "aa"取指定的 alias 所表示的最终的 beanName ,例如别名 A 指向别名 B的 bean 则返回 B ;若别名 A 指向别名 B,别名 B 又指向别名 C的Bean,则直接返回 C单例的在 Spring 的同一个容器内只会被创建一次,后续再获取 Bean ,就直接从单例缓存中获取了,当然,这里也只是尝试加载,首先会尝试从缓存中加载,如果加载不成功,则尝试从 singletonFactroy 中加载,因为为创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,在 Spring 中创建 Bean 的原则是不等 bean 创建完成就会将创建的 bean 的 ObjectBeanFactory 提前曝光加入到缓存中的一旦下一个 bean 创建的时候需要依赖上一个 bean 则直接使用BeanFactory

  2. bean 的实例化
    如果从缓存中得到 bean 的原始状态,则需要对 bean 进行实例化,这里有必要强调一下, 缓存中的记录只是原始的 bean 的状态,并不一定是我们最终想要的 bean ,举个例子,但是我们真正需要的是工厂 bean 中定义的 factory-method 方法中返回的 bean,而 getObjectForBeanInstance 就完成,了这个工作,后续会详细的讲解

  3. 原型模式的依赖检查

    只有在单例的情况下,才会尝试解决的循环依赖,如果存在 A中有 B 的属性,B 中有 A 的属性,那么当依赖注入的时候,就会产生 A 还未创建
    完成的时候,因为对于 B 的创建再次返回创建 A ,造成循环依赖,也就是情况,isPrototypeCurrentlyInCreation(beanName) 判断 true检测 parentBeanFactory
    从代码的上来看,如果缓存没有数据的话,直接转到父类的工厂上去加载了,这是为什么呢?
    可能读者会忽略一个很重要的判断条件,parentBeanFactory !=null && !containsBeanDefinition(beanName),parentBeanFactory !=null ,parentBeanFactory 如果为空,则其他的一切都是浮云,但是!containsBeanDefinition(beanName) 就比较 重要了,它是在检测如果当前加载的 xml 配置文件中不包含 beanName 所对应的配置,就只能到 parentBeanFactory 去尝试一下,然后再去递归的调用 getBean 方法,将存储的 xml 配置文件中的 GenericBeanDefinition 转换成 RootBeanDefinition 中的,但是所有的 Bean后续处理都是针对RootBeanDefinition的,所以这里需要转换,转换的同时如果父类 bean 不为空的话,则会一并合并父类的属性

  4. 寻找依赖
    因为 bean 初始化的过程很可能是会用到某些属性的,而某些属性很可能是动态配置的,并且配置成依赖于其他的 bean , 那么
    这个时候就有必要加载依赖的bean ,所以,在 Spring 的加载顺序中,在初始化某一个 bean 的时候,首先会初始化这个 bean 所对应的依赖

  5. 针对不同的 scope 进行 bean 的创建
    我们都知道,在 Spring 中存在着不同的 scope ,其中默认的是 singleton ,但是还有一些其他的配置,诸如 prototype ,request 之类的
    在这个步骤中,Spring会根据不同的配置进行不同的初始化策略

  6. 程序到这里返回 bean后已经基本的结果了,通常对该方法的调用参数 requiredType 是为空的,但是可能会存在这样的一种情况,返回的 bean
    其实是 String 类型的,但是 requiredType 传入的是 Integer类型,那么这个时候本步骤会直到了作用,它的功能是将返回bean 转换成requiredType 所指定的类型,当然,String 转换为 Integer 是最简单的一种转换,在 Spring 提供了各种各样的转换器,用户也可以自己定义
    自己的转换器来满足需求
    经过上面的步骤后bean 的加载已经结束了,这个时候就可以返回我们需要的 bean 了,直观的反映整个过程,其中最重要的步骤就是8,针对不同的
    scope 进行 bean 的创建,你会看到各种常用的 Spring中提供了各种各样的转换器,用户也可以自己扩展转换器来满足需求。

经过上面的步骤后,bean 的加载已经结束,这个时候就可以返回我们所需要的 bean 了。

DefaultSingletonBeanRegistry.java

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
	Assert.notNull(beanName, "'beanName' must not be null");
	// 全局变量需要同步
	synchronized (this.singletonObjects) {
		// 首先检查对应的bean 是否已经加载过,因为 singleton 模式其实就是复用以创建 bean ,这一步是必须的
		Object singletonObject = this.singletonObjects.get(beanName);
		// 如果为空才可以进行 singletonObject == null
		if (singletonObject == null) {
			if (this.singletonsCurrentlyInDestruction) {
				throw new BeanCreationNotAllowedException(beanName,
						"Singleton bean creation not allowed while the singletons of this factory are in destruction " +
						"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
			}
			// 在创建单例前调用
			beforeSingletonCreation(beanName);

			boolean newSingleton = false;
			boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
			if (recordSuppressedExceptions) {
				this.suppressedExceptions = new LinkedHashSet<Exception>();
			}
			try {
				// 初始化 bean
				singletonObject = singletonFactory.getObject();
				newSingleton = true;
			}
			catch (IllegalStateException ex) {
				singletonObject = this.singletonObjects.get(beanName);
				if (singletonObject == null) {
					throw ex;
				}
			}
			catch (BeanCreationException ex) {
				if (recordSuppressedExceptions) {
					for (Exception suppressedException : this.suppressedExceptions) {
						ex.addRelatedCause(suppressedException);
					}
				}
				throw ex;
			}
			finally {
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = null;
				}
				// 在单例创建后调用
				afterSingletonCreation(beanName);
			}

			if (newSingleton) {
				// 加入缓存中
				addSingleton(beanName, singletonObject);
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}
}

之前我们已经讲解了从缓存中获取单例的过程,那么,如果缓存中不存在已经加载的单例 bean ,就需要从头开始 bean 的加载过程了,而 Spring
中使用 getSingleton 的重载方法实现了 bean 的加载过程
上述代码中其实使用了回调方法,使得程序可以在单例创建前后做一些准备及处理操作,而真正的获取单例 bean 的方法其实并不是在此方法中实现在
其实逻辑是在 ObjectFactory 类型的实例 singleFactory 中实现的,而这些准备及处理操作包括如下内容:

  1. 检查缓存中是否已经加载过
  2. .若没有加载,则记录 beanName 的正在加载状态
  3. 加载单例前记录加载状态
    可能你会觉得 beforeSingletonCreation 方法是空实现,里面没有任何逻辑,但是其实不是,这个函数中做了一个很重要的操作,记录加载状态,也就是通过 this.singletonsCurrentlyIn 这个函数做一个很重要的操作,记录加载状态,也就是通过 is.singletonsCurrentlyInCreation.add(beanName )
    将当前正要创建的 bean 记录在缓存中,这样便可以对我一依赖进行检测
    protected void beforeSingletonCreation(String beanName ){
            if(!this.inCreationCheckExclusions.contains(beanName ) && !this.singletons.CurrentlyInCreation.add(beanName )){
                    throw new BeanCurrentlyInCreationException(beanName);
            }
    }
  4. 通过调用参数传入的 ObjectFacotry 的个体 Object 方法实例化 bean
  5. 加载单例后的处理方法调用
    同步骤3的记录加载状态相似,当 bean 加载结束后需要移除缓存中对该 bean 的正在加载状态记录
    protected void afterSingletonCreation(String beanName ){
            if(!this.inCreationCheckExclusions.contains(beanName) &&         !this.singletons.CurrentlyInCreation.remove(beanName)){
                    throw new IllegalStateException(“Single '” + beanName + " ’ isnt current in creation ")
            }
    }
  6. 将结果记录至缓存中并删除加载bean 的过程中所记录的各种辅助状态
    protected void addSingleton(String beanName ,Object singletonObject){
            synchronized(this.singletonObjets){
                    this.singletonObjects.put(beanName,(singletonObject == null ? singletonObject:NULL_OBJECT));
                    this.singletonFactories.remove(beanName);
                    this.earlySingletonObjects.remove(beanName);
                    this.registereSingletons.add(beanName);
            }
    }
  7. 返回处理结果
    虽然我们已经从外部了解了加载 bean 的逻辑架构,但现在我们还并没有开始对 bean 的加载功能的探索,之前反映到过,bean 的加载逻辑其实
    是在传入的 ObjectFactory 类型参数 singletonFactory 中定义的,我们反推参数的获取 ,得到如下的代码
	sharedInstance=getSingleton(beanName ,new ObjectFactory<Object> (){
		public Object getObject() throws BeanException{
	       try{
	       return createBean(beanName ,mbd,args);
	       }catch(Exception ex ){
	           destroySingleton(beanName);
	           throw ex;
	       }
	   }
	});

ObjectFactory 的核心的部分其实只是调用了 createBean的方法,所以我们还需要到 createBean 方法中追寻真理

AbstractAutowireCapableBeanFactory.java

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
	if (logger.isDebugEnabled()) {
		logger.debug("Creating instance of bean '" + beanName + "'");
	}
	RootBeanDefinition mbdToUse = mbd;
	// 判断需要创建的Bean是否可以实现实例化,即是否可以通过当前的类加载器加载
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}

	// 校验和准备Bean方法的覆盖
	try {
		// 验证及准备覆盖方法
		mbdToUse.prepareMethodOverrides();
	}
	catch (BeanDefinitionValidationException ex) {
		throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
				beanName, "Validation of method overrides failed", ex);
	}

	try {
		// 如果Bean配置了初始化和初始化后的处理器,则试图返回一个需要创建的Bean的代理对象
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
	}
	catch (Throwable ex) {
		throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
				"BeanPostProcessor before instantiation of bean failed", ex);
	}
	// 创建Bean的入口
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
	if (logger.isDebugEnabled()) {
		logger.debug("Finished creating instance of bean '" + beanName + "'");
	}
	return beanInstance;
}

准备创建bean
我们不可能指望在一个函数中完成一个复杂的逻辑,而且我们跟踪了这么多的Spring代码,经历了这么多的函数,或多或少的发现了一些规律
: 一个真正干活的函数其实是以do开头的,比如doGetObjectFromFactoryBean,而给我们错觉的函数,比如getObjectFromFactoryBean
,其实只是从全局的的角度去统筹的工作,这个规则对于createBean也不例外,我们看看createBean函数做了哪些准备工作。

从代码中我们可以总结出函数完成的具体的步骤及功能

  1. 根据设置的 class 属性或者根据 className 来解析 Class
  2. 对 overide 属性来进行标记及验证
    很多的读者可能会不知道这个方法的使用是什么,因为Spring在配置里根本就没有诸如ovrride-method之类的配置,那么这个方法到底是干什么用的呢?
    其实在Spring中确实没有override-method这样的配置,但是如果读过前面的部分,可能会有所发现,在Spring配置中是存在lookup-method和
    replace-method的,而这两个配置的加载其实就是将配置统一存在在beanDefinition中的methodOverrides的属性里,而这个函数的操作
    其实也是针对于这两个配置的。
  3. 应用初始化前的后处理器,解析指定的bean是否在初始化前短路操作。
  4. 创建bean

到这里,我们终于完成了一轮 bean 的解析,在创建TestA 对象是,调用resolveConstructorArguments方法解析构造函数参数,而我们知道ref属性是使用RuntimeBeanReference对象封装的,而引用类型的属性由resolveReference方法解析。在这个方法中,重新调用 getBean方法。
简单的来说,就是 TestA 在创建时,因为构造函数需要,需要 调用 getBean方法获取 TestB,而 TestB在创建时需要获取到 TestC ,而 TestC 在创建时,构造函数需要 TestA
又回到了 getSingleton方法的调用。
而在 getSingleton 方法中有一个方法
protected void beforeSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
        }
}
而每次创建单例时会将 bean 的名称加入到singletonsCurrentlyInCreation集合中,而在创建 TestC 时,构造函数依赖注入 TestA ,而 TestA在创建之初就己经加入到了singletonsCurrentlyInCreation集合中,因此,在再次创建时,抛出BeanCurrentlyInCreationException异常。在这里插入图片描述

为什么 setter 注入的时候,就能注入成功呢?
下面我们简单的分析一下。其实 setter注入的方式和构造器注入的方式很多都相同的。这里挑一些不同的地方来说一下。
在这里插入图片描述
从上图中得知,构造器注入时,每一次都没有走过 createBeanInstance 方法,而 setter 注入时是通过 populateBean 方法来进行属性注入的。
在这里插入图片描述
而在 getSingleton 方法中的 singletonFactory.getObject()的方法后面有一个重要的方法。
addSingleton方法。

protected void addSingleton(String beanName, Object singletonObject) {
	synchronized (this.singletonObjects) {
		this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
		this.singletonFactories.remove(beanName);
		this.earlySingletonObjects.remove(beanName);
		this.registeredSingletons.add(beanName);
	}
}

而在这个方法中,有一行重要的操作,就是将BeanFactory保存到singletonObjects中。因此,在 doGetBean 方法中。TestC 对象依赖注入 TestA 时,这个时候调用 doGetBean(“TestA”),先调用 getSingleton(“TestA”,true) 。
在这里插入图片描述
在这里插入图片描述
获取到从 createBeanInstance()方法返回回来的 bean 对象。
在这里插入图片描述
因此,通过 setter 方法能够获取到 bean对象。
下面我们来总结一下。

1.构造器注入

  • Spring 容器创建"testA" bean,首先去"当前创建的 bean"池中查找是否当前的bean
    正在创建,如果没有发现,则继续准备其需要的构造器参数"testB",并将"testA" 标识符放到"当前创建的 bean池" 中。
  • Spring 容器创建"testB",首先去当前创建的 bean 池中,查找是否当前 bean 正在创建
    ,如果没有发现,则继续准备其需要的构造器参数"testC",并将"testB" 标识符放到当前创建的 bean 池中。
  • Spring容器创建"testC"bean 时,首先去"当前创建的 bean 池中" 查找 是否当前的 bean 正在创建,如果没有发现,则继续准备创建其所需要的"testA" ,并将"testC" 标签符放到"当前创建的 bean 池"中。
  • 到此为止,Spring 容器去创建 “testA"bean 发现该 bean 标识符在"当前创建的 bean” 池中,因为表示循环依赖,抛出 BeanCurrentlyInCreationException。

2.setter循环依赖

        表示通过 setter 注入的方式构成循环依赖,对于 setter 注入造成的依赖是通过 Spring 容器提前暴露刚完成构造器注入但未完成其他的步骤(如 setter 注入) 的 bean 来完成的,而且只能解决单例作用域 bean 循环依赖,通过提前暴露一个单例工厂方法,从而使其他 bean 能引用到该 bean,如代码所示
addSingletonFactory(beanName,new ObjectFactory(){
        public Object getObject() throws BeanException{
                return getEarlyBeanReference(beanName,mbd,bean);
        }
})
具体的步骤如下:

  1. Spring 容器创建单例"testA"bean,首先根据无参的构造器创建 bean,并暴露一个"ObjectFactory" 用于返回一个提前暴露一个创建中的 bean,并将"testA" 标识放到"当前的创建的 bean 池" 中,然后进行 setter 注入"testB"
  2. Spring 容器创建单例"testB"bean,首先根据无参构造器创建 bean,并暴露一个"ObjectFactory"用于返回一个提前暴露一个创建中的 bean,并将"testB" 标识放到"当前创建的 bean 池"中,然后进行 setter 注入"circle"
  3. Spring 容器创建单例"testC"bean,首先根据无参构造器创建 bean,并暴露一个"ObjectFactory" 用于返回一个提前暴露一个创建中的 bean,并将"testC" 标识符放到当前创建的 bean池中,然后进行 setter 注入"testA",进行注入"testA"时由于提前暴露了"ObjectFactory"工厂,从而使用它们返回一个提前暴露一个创建中的 bean。
  4. 最后在依赖注入"testB" 和"testA",完成 setter 注入。

3.prototype范围的依赖处理

对于 “prototype"作用域 bean,Spring 容器无法完成依赖注入,因为 Spring容器不进行缓存"prototype” 作用域 bean,因此无法提前暴露一个创建中的 bean,示例如下:
1.创建配置文件

spring37_3.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="testA" class="com.spring_1_100.test_31_40.test37.TestA" scope="prototype">
        <property name="testB" ref="testB"></property>
    </bean>

    <bean id="testB" class="com.spring_1_100.test_31_40.test37.TestB" scope="prototype">
        <property name="testC" ref="testC"></property>
    </bean>

    <bean id="testC" class="com.spring_1_100.test_31_40.test37.TestC" scope="prototype">
        <property name="testA" ref="testA"></property>
    </bean>
    
</beans>

测试

@Test
public void test3() {
    ApplicationContext bf = new ClassPathXmlApplicationContext("classpath:spring_1_100/config_31_40/spring37_3.xml");
    System.out.println(((TestA) bf.getBean("testA")).getTestB().getTestC().getTestA());
}

在这里插入图片描述

前面对于 构造器循环依赖,setter 循环依赖己经做了详细的分析,关于prototype范围的依赖处理,这里就不做过多的缀述了,有兴趣的小伙伴,自行去研究。一定要调试。

本文的 github 地址是
https://github.com/quyixiao/spring_tiny/tree/master/src/main/java/com/spring_1_100/test_31_40/test37

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值