循环依赖:如果使用构造函数注入,则可能创建无法解决的循环依赖,所以尽量使用构造set方法注入。
1.构造函数
@Component
public class ServiceA {
private ServiceB serviceB;
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
@Component
public class ServiceB {
private ServiceA serviceA;
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
}
public static void main(String[] args) throws InterruptedException{
new ServiceA(new ServiceB(new ServiceA(......))) // 一直new下去
}
2.set方法
public class ServiceAA {
private ServiceBB serviceBB;
public void setServiceBB(ServiceBB serviceBB) {
this.serviceBB = serviceBB;
System.out.println("A 里面设置了B");
}
}
public class ServiceBB {
private ServiceAA serviceAA;
public void setServiceAA(ServiceAA serviceAA) {
this.serviceAA = serviceAA;
System.out.println("B 里面设置了A");
}
}
public static void main(String[] args) throws InterruptedException{
//new ServiceA(new ServiceB(new ServiceA()))
ServiceAA a = new ServiceAA();
ServiceBB b = new ServiceBB();
b.setServiceAA(a);
a.setServiceBB(b);
}
3.使用Spring容器创建
public class A {
private B b;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
public A() {
System.out.println("---A created success");
}
}
public class B {
private A a;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
public B() {
System.out.println("---B created success");
}
}
public class ClientSpringContainer {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
A a = context.getBean("a", A.class);
B b = context.getBean("b", B.class);
}
}
scope="singleton"不会产生循环依赖
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="b" class="com.atguigu.study.spring.circulardepend.B" scope="singleton">
<property name="a" ref="a"/>
</bean>
<bean id="a" class="com.atguigu.study.spring.circulardepend.A" scope="singleton">
<property name="b" ref="b"/>
</bean>
</beans>
scope="prototype"会产生循环依赖,报错部分信息如下:
......:Is there an unresolvable circular reference?
4.Spring怎么解决循环依赖的
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
protected final Log logger = LogFactory.getLog(this.getClass());
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
private final Map<String, Object> earlySingletonObjects = new HashMap(16);
private final Set<String> registeredSingletons = new LinkedHashSet(256);
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap(16));
private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap(16));
在DefaultSingletonBeanRegistry 类中使用三个不同的Map,分别是singletonObjects是一级缓存,earlySingletonObjects是二级缓存,singletonFactories是三级缓存。
只有单例bean会通过三级缓存提前暴露来解决循环依赖的问题,而非单例的bean,每次从容器中获取都是一个新的对象,都会重新创建,所以非单例bean是没有缓存的,不会将其放在三级缓存中。