spring循环依赖常见问题?

179 阅读2分钟

一、完整表述spring的bean的生命周期?

1)实例化Bean对象(在jvm的堆上开配内存空间)。

2)初始化Bean对象(set()方法注入属性值)。

3)如果 Bean对象实现了BeanNameAware接口,需要实现setBeanName() 方法,设置bean的名字。

4)如果 Bean对象实现了BeanClassLoaderAware接口,调用setBeanClassLoader() 方法,传入Classloader对象的实例。

5)如果有和加载这个Bean的spring容器相关BeanPostProcessor对象执行postProcessBeforeInitiallization() 方法

6)如果Bean实现了InitializingBean 接⼝,执⾏afterPropertiesSet() ⽅法;如果 Bean 在配置⽂件中的定义包含 init-method 属性,执⾏指定的⽅法。

7)如果有和加载这个 Bean的 Spring 容器相关的 BeanPostProcessor 对象,执⾏postProcessAfterInitialization() ⽅法。

8)当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接⼝,执⾏ **destroy() **;当要销毁 Bean 的时候,如果 Bean 在配置⽂件中的定义包含 destroy-method 属性

二、是什么是spring的循环依赖?

@Component
publicclass A {

    @Autowired
    private B b;

}
@Conponent
publicclass B {

    @Autowired
    private A a;
}

三、spring的循环依赖怎么解决?

	/** Cache of singleton objects: bean name to bean instance. */
        // 一级缓存
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
	// 三级缓存
	/** Cache of singleton factories: bean name to ObjectFactory. */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    
	// 二级缓存
	/** Cache of early singleton objects: bean name to bean instance. */
	private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
    
    /** 创建时缓存 bean在创建时会放在缓存中,创建成功后移除缓存。
    private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

四、一级缓存能不能解决循环依赖?

答:不能。 在三个级别的缓存中,放置的对象是有区别的(1、完成实例化且初始化对象 2、实例化未完成初始化对象),但是如果只有一级缓存,在并发条件下就有可能取到未初始化的对象,属性值都是null。

五、二级缓存能不能解决循环依赖?为什么要使用三级缓存来解决循环依赖问题?

答:二级缓存理论上可以解决。 但是要注意了:为什么要在三级缓存中防止匿名内部类?

本质在于为了创建代理对象,假如现在有A类,需要生成代理对象,需要实例化。

三级缓存中放置的是生成具体对象的一个匿名内部类,这个匿名内部类可能是代理类,也可能是普通的实例对象,而使用三级缓存就保证了不管是否是要代理对象,都保证是用一个对象,而不会是前面使用普通bean后面是代理类。保证一致性。

六、为什么构造器方式无法解决循环依赖问题?

答: 原因在与此方式 实例化初始化分开(实例化时不给属性赋值)操作,将提前实例化好的对象提前暴露出去,供别人调用,而使用构造器的时候,必须要调用构造方法,没有构造方法无法完成对象的实例化操作,从而陷入死循环中。