您的位置:首页 > 编程语言 > Java开发

spring源码(12)加载指定bean前,先加载依赖的bean

2017-08-15 23:20 357 查看


接着看bean的加载过程,本节来看看如何递归实例化依赖的bean。

一、bean标签的depends-on属性

Spring Framework Reference Documentation 6.4.3. Using depends-on

该节详细介绍了 bean的depends-on,下面简单复习一下:

If a bean is a dependency of another that usually means that one bean is set as a property of another.
Typically you accomplish this with the <ref/> element in XML-based configuration metadata.
However, sometimes dependencies between beans are less direct;
The depends-on attribute can explicitly force one or more beans to
be initialized before the bean using this element is initialized.
The following example uses the depends-on
attribute to express a dependency on a single bean:


如果一个A bean是B bean的依赖,那么一般意味着A bean是B bean的一个属性。在XML配置文件中可以通过ref属性,将B bean设为A bean的属性。但是,这只是一般情况,还有一些情况虽然A bean是B bean的依赖,仅仅意味着在加载B bean时,要先加载A bean。看下面的例子:

<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />


To express a dependency on multiple beans, supply a list of bean names
as the value of the depends-on attribute, with commas, whitespace and semicolons, used as valid delimiters:


如果想要表达依赖多个bean,可以使用逗号,空格和分号作为多个beand分隔符,看下面的例子:

<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>

<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />


特别注意:

在单例情况下,可以指定相互依赖bean之间的销毁顺序。

如果A bean是B bean的依赖,则在销毁B bean时,A bean先被销毁。


二、代码分析

String[] dependsOn = mbd.getDependsOn();
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 + "'");}
registerDependentBean(dep, beanName);
getBean(dep);
}
}


首先获取所依赖的所有bean。

在DefaultSingletonBeanRegistry中有两个属性,分别是:

/** Map between dependent bean names: bean name --> Set of dependent bean names */
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

/** Map between depending bean names: bean name --> Set of bean names for the bean's dependencies */
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);


dependentBeanMap :key-被依赖的bean value-依赖者

dependenciesForBeanMap :key-依赖者 value-被依赖的bean

通过断点来试验一下:

<bean id="A" class="com.demo.app.Cat" depends-on="B;C"></bean>

<bean id="B" class="com.demo.app.Cat"></bean>

<bean id="C" class="com.demo.app.Cat" depends-on="B;D"></bean>

<bean id="D" class="com.demo.app.Cat"></bean>


public static void main(String[] args) {

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("springContext.xml"));
Cat cat = (Cat) bf.getBean("A");
}






没啥问题!

接下来会判断是否循环依赖,如果是则抛出异常。

protected boolean isDependent(String beanName, String dependentBeanName) {
return isDependent(beanName, dependentBeanName, null);
}


private boolean isDependent(String beanName, String dependentBeanName, Set<String> alreadySeen) {
if (alreadySeen != null && alreadySeen.contains(beanName)) {
return false;
}
String canonicalName = canonicalName(beanName);
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null) {
return false;
}
if (dependentBeans.contains(dependentBeanName)) {
return true;
}
for (String transitiveDependency : dependentBeans) {
if (alreadySeen == null) {
alreadySeen = new HashSet<>();
}
alreadySeen.add(beanName);
if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
return true;
}
}
return false;
}


在上面的代码中通过递归的方式来判断是否存在循环依赖。

假如 A 依赖 B,查看B是否也依赖A,如果是则返回false。

当然没有这简单。

假如:

A 依赖 B

C、D依赖 A ,

spring还会去判断 B与C,B与D是否循环依赖。

我也不知道应该用什么图来表达递归,很烦!

public void registerDependentBean(String beanName, String dependentBeanName) {
// A quick check for an existing entry upfront, avoiding synchronization...
String canonicalName = canonicalName(beanName);
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans != null && dependentBeans.contains(dependentBeanName)) {
return;
}

// No entry yet -> fully synchronized manipulation of the dependentBeans Set
synchronized (this.dependentBeanMap) {
dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null) {
dependentBeans = new LinkedHashSet<>(8);
this.dependentBeanMap.put(canonicalName, dependentBeans);
}
dependentBeans.add(dependentBeanName);
}
synchronized (this.dependenciesForBeanMap) {
Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);
if (dependenciesForBean == null) {
dependenciesForBean = new LinkedHashSet<>(8);
this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
}
dependenciesForBean.add(canonicalName);
}
}


这段代码就是讲依赖关系存入dependentBeanMapdependenciesForBeanMap,很简单。

记录bean之间的依赖关系有两方面的作用:

1.避免循环依赖

2.在单例情况下,可以指定相互依赖bean之间的销毁顺序
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息