下面是对于“Spring解决循环依赖问题及三级缓存的作用”的详细讲解:
一、什么是循环依赖问题?
在Spring中循环依赖是指两个或多个Bean互相依赖而形成的闭环,这样的循环依赖问题会导致Bean不能正确地完成依赖注入过程,从而导致应用程序启动失败。在依赖注入时,如果两个Bean之间相互依赖,但它们两个都没在容器中加载完成,那么就会出现循环引用的问题。例如,两个Bean有相互依赖的关系,当创建Bean A时,需要Bean B的某些属性值,而当创建Bean B时,也需要Bean A的某些属性值,这时就会形成循环依赖问题。
Spring提供了两种解决循环依赖的机制:通过BeanPostProcessor解决、使用三级缓存解决。
二、如何使用BeanPostProcessor解决循环依赖问题?
- 关于BeanPostProcessor
BeanPostProcessor是Spring框架中新增的特殊方法调用机制,它允许在BeanFactory组装Bean的过程中尽早的拦截到每个Bean,并进行一些增强或者替换,是SpringAOP的核心之一。
通过自定义BeanPostProcessor,可以在bean中指定需要解决的循环依赖,从而避免环依赖导致的问题。
-
示例说明
-
添加两个类:A和B
public class A {
public B b;
public void run() {
......
}
}
public class B {
public A a;
public void run() {
......
}
}
- 解决方案
定义一个MyBeanPostProcessor,对bean进行特殊处理,解决循环依赖问题。
public class MyBeanPostProcessor implements BeanPostProcessor {
private Map<String, Object> beanMap = new ConcurrentHashMap<>();
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
beanMap.put(beanName, bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//1.先要判断当前的bean是否依赖了其他bean
if (bean instanceof A) {
A a = (A) bean;
if (a.b == null){
a.b = (B) beanMap.get("B");
}
} else if (bean instanceof B) {
B b = (B) bean;
if (b.a == null) {
b.a = (A) beanMap.get("A");
}
}
return bean;
}
}
三、如何使用三级缓存解决循环依赖问题?
- 关于三级缓存
Spring容器初始化时,会先将BeanDefinition缓存到BeanDefinitionMap中,然后再把实例对象缓存到singletonObjects中,这就是Spring IOC容器的一级缓存和二级缓存,而三级缓存则是用来解决循环依赖问题的。
-
示例说明
-
添加两个类:C和D
public class C {
public D d;
public void run() {
......
}
}
public class D {
public C c;
public void run() {
......
}
}
- 解决方案
在创建Bean时,当发现Bean正在创建中,则会将当前正在创建的Bean对象缓存到“三级缓存”中,等待整个Bean创建完毕后再进行属性注入。
public class MyClassPathXmlApplicationContext extends AbstractApplicationContext {
private final ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
//...
private final Map<String, Object> singletonFactories = new ConcurrentHashMap<>(256);
private final Map<String, Object> earlySingletonObjects = new HashMap<>(256);
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//...
private void doCreateBean(String beanName, BeanDefinition beanDefinition) {
Object singletonObject = getSingleton(beanName);
if (singletonObject != null) {
return singletonObject;
}
//...
createBeanInstance(beanName, beanDefinition);
//...
this.factoryBeanObjectCache.put(beanName, new Object[]{mbd, bean});
}
protected Object createBeanInstance(String beanName, BeanDefinition beanDefinition) {
Object bean;
try {
//创建Bean实例
bean = beanDefinition.getBeanClass().newInstance();
} catch (Exception e) {
//...
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, beanDefinition, bean));
//...
return bean;
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.isTrue(!this.singletonFactories.containsKey(beanName), "bean factory already registered for bean \"" + beanName + "\"");
//缓存三级缓存
this.earlySingletonObjects.put(beanName, singletonFactory);
}
protected Object getEarlyBeanReference(String beanName, BeanDefinition beanDefinition, Object bean) {
Object exposedObject = bean;
String[] dependsOn = beanDefinition.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
if (isDependent(beanName, dependsOnBean)) {
registerDependentBean(dependsOnBean, beanName);
}
getBean(dependsOnBean);
}
}
return exposedObject;
}
//...
}
以上就是通过三级缓存解决循环依赖问题的过程示例。
希望以上的详细讲解能够对你有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring解决循环依赖问题及三级缓存的作用 - Python技术站