美文网首页
spring depends-on的用法,以及为什么不能循环依赖

spring depends-on的用法,以及为什么不能循环依赖

作者: guessguess | 来源:发表于2020-06-29 11:37 被阅读0次

先以xml方式,首先添加俩个类 A,B

public class A {

    private B b;

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }   
}
public class B {
}

下面上配置文件

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

    <bean name="a" class="com.gee.demo.entity.A" depends-on="b" ></bean>
    <bean name="b" class="com.gee.demo.entity.B"></bean>
</beans>

测试方法

public class Config {   
    public static void main(String args[]) {
        ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:application-config.xml");
        System.out.println(applicationContext.getBean(A.class));
        System.out.println(applicationContext.getBean(B.class));
    }
}

最后输出
com.gee.demo.entity.A@45afc369
com.gee.demo.entity.B@799d4f69
说明注入是成功的

那么试一下注解方式
调整A,B的代码

@Component
@DependsOn(value = "b")
public class A {
    
}
@Component
public class B {

}

测试方法

@Configuration
@ComponentScan(basePackages = "com.gee")
public class Config {
    public static void main(String args[]) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
        System.out.println(applicationContext.getBean(A.class));
        System.out.println(applicationContext.getBean(B.class));
    }
    
}

最后输出
com.gee.demo.entity.A@2aa3cd93
com.gee.demo.entity.B@7ea37dbf
说明是成功的

那么下面问题来了,互相依赖会怎么办
此时我们调整代码

@Component
@DependsOn(value = "b")
public class A {
    
}
@Component
@DependsOn(value = "a")
public class B {

}

再次执行同样的测试方法,抛出异常。

警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in file [/Users/huangzhaoji/eclipse-workspace/springframework-demo/target/classes/com/gee/demo/entity/B.class]: Circular depends-on relationship between 'b' and 'a'

调整xml,改为A,B相互依赖

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">      
    <bean name="a" class="com.gee.demo.entity.A" depends-on="b" ></bean>
    <bean name="b" class="com.gee.demo.entity.B" depends-on="a"></bean>
</beans>

运行xml的测试方法

public class Config {   
    public static void main(String args[]) {
        ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:application-config.xml");
        System.out.println(applicationContext.getBean(A.class));
        System.out.println(applicationContext.getBean(B.class));
    }
}

此时就报错了。
在DefaultSingletonBeanRegistry有一个方法是用于判断,是否出现循环依赖的。

private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
        if (alreadySeen != null && alreadySeen.contains(beanName)) {
            return false;
        }
        String canonicalName = canonicalName(beanName);
        //其实这个map就记录了依赖于这个类的所有类
        Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
        if (dependentBeans == null) {
            return false;
        }
        //若依赖b的类,包含a,而此时b依赖a,则说明是循环依赖,返回true,随后就会抛出异常了。
        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;
    }

相关文章

网友评论

      本文标题:spring depends-on的用法,以及为什么不能循环依赖

      本文链接:https://www.haomeiwen.com/subject/rsjlxktx.html