spring的循环依赖是个老生常谈的话题,熟悉spring或者准备面试的同学肯定都在熟悉不过了。闲来无事记录下我对spring循环依赖问题及三级缓存的理解。
首先来看下准备工作。首先准备A、B两个类互相依赖,一个config类、一个测试启动类。
A类如下:加上注解,一个属性b,get set方法,没了!
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class A {
@Autowired
private B b;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
B类如下:加上注解,一个属性a,一个测试用的query方法,get set 方法,没了!
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class B {
@Autowired
private A a;
public void query(){
System.out.println("bbbbb");
}
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
}
Config类如下:扫描包,没了!
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.zlb.ioc")
public class IocConfig {
}
测试启动类如下:构建spring环境,从容器中获取bean,调用方法。没了!
import com.zlb.ioc.circle.A;
import com.zlb.ioc.config.IocConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Demo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(IocConfig.class);
A a = context.getBean(A.class);
a.getB().query();
}
}
我们来扫个盲,说两个前置知识:
1.我们都知道spring是一个容器,那么我们想从容器中获取一个bean的时候一定会调用一个getBean方法,无论是我们手动从context获取还是属性注入的时候spring内部去获取,都是走这个getBean方法。
2.spring中的三级缓存指的是下边这三个货。其实就是三个map,只不过泛型有一个特殊一点。至于谁是一级谁是二级这个仁者见仁,本文直接用变量名以防混乱。
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 ConcurrentHashMap<>(16);
在看源码之前我们通过文字捋一遍整体流程:
- 首先创建对象A,调用getBean("a")方法。
- 从缓存singletonFactories中获取对象A,此时获取不到,于是反射创建对象A。
- 将对象A标记为正在创建中。
- 将对象A放进缓存singletonFactories。
- 创建A的过程中发现要给属性b赋值,于是满世界找对象B。
- 通过getBean("b")方法获取B对象。
- 创建B的过程发现要给属性a赋值,于是满世界找对象A。
- 再次调用getBean("a")方法获取A对象。
- 从缓存singletonFactories中拿到A对象返回B,于是B对象创建完成并放进缓存。
- B创建完成于是返回给第5步,最终A对象创建完成。
最后走进spring源码,看看大佬们创造的艺术世界:
1.一切都要从spring容器初始化开始说起:
public class Demo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(IocConfig.class);
A a = context.getBean(A.class);
a.getB().query();
}
}
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
//进入refresh方法
refresh();
}
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 进入这个方法
finishBeanFactoryInitialization(beanFactory);
}
}
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 进入这个方法 具体实现是DefaultListableBeanFactory
beanFactory.preInstantiateSingletons();
}
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
//进入这个方法
getBean(beanName);
}
}
}
2.重点终于来了,这是第一次调用getBean方法,此时是获取(创建)对象A:
@Override
public Object getBean(String name) throws BeansException {
//进去
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
// 首先尝试从缓存中去获取 第一次肯定是获取不到的
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
try {
// Create bean instance.
if (mbd.isSingleton()) {
//创建bean实例
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
3.我们看下getSingleton(beanName)这个方法是怎么获取的?
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
// 首先从singletonObjects缓存中获取 第一次肯定拿不到
Object singletonObject = this.singletonObjects.get(beanName);
//第二个条件是判断当前bean是否正在创建中(正在创建中的bean都会放在一个集合里边),第一次创建的时候当前bean肯定不在这个集合中 所以这个if判断不成立 直接返回null
// 但是如果是第二次来获取,也就是说循环依赖中给B对象的a属性赋值的时候,此时a已经在集合中了即a已经是正在创建中的状态了,所以if条件成立。
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//从earlySingletonObjects缓存中获取 无论是第一次还是第二次都拿不到
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) { //allowEarlyReference恒为true
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
// 从singletonObjects缓存中获取 无论是第一次还是第二次都拿不到
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//拿不到
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
//第二次获取的时候singletonFactories缓存中已经有值了 只不过存的是一个工厂的函数式接口
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//此时此刻就会去执行函数式接口的具体实现 也就是AbstractAutowireCapableBeanFactory.getEarlyBeanReference方法
singletonObject = singletonFactory.getObject();
//放入earlySingletonObjects缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
4.再来看下创建对象的getSingleton方法:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 再次从singletonObjects缓存中获取 肯定还是获取不到
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
//将正在创建的对象放到集合中 表示:当前对象正在创建中
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//此处是调用方法入参中的第二个参数 即:lambda表达式
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
//从正在创建的集合中删除
afterSingletonCreation(beanName);
}
if (newSingleton) {
//将当前bean放入singletonObjects缓存中
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
5.看看createBean方法中的doCreateBean(beanName, mbdToUse, args)方法:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//反射创建bean实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//将当前半成品bean放入singletonFactories缓存中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//属性赋值
populateBean(beanName, mbd, instanceWrapper);
//回调初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
return exposedObject;
}
6.populateBean方法中会给A对象的b属性赋值,此时会再次调用getBean方法,只不过此时要获取的是B对象了。代码和上边一模一样,直到再次执行到populateBean方法给B对象的a属性赋值的时候。此时会第三次执行getBean方法,不过此时获取的又是A对象了。那我们再看下第二次获取A时从缓存获取时候的逻辑:
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
// 首先从singletonObjects缓存中获取 第一次肯定拿不到
Object singletonObject = this.singletonObjects.get(beanName);
//第二个条件是判断当前bean是否正在创建中(正在创建中的bean都会放在一个集合里边),第一次创建的时候当前bean肯定不在这个集合中 所以这个if判断不成立 直接返回null
// 但是如果是第二次来获取,也就是说循环依赖中给B对象的a属性赋值的时候,此时a已经在集合中了即a已经是正在创建中的状态了,所以if条件成立。
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//从earlySingletonObjects缓存中获取 无论是第一次还是第二次都拿不到
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) { //allowEarlyReference恒为true
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
// 从singletonObjects缓存中获取 无论是第一次还是第二次都拿不到
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//拿不到
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
//第二次获取的时候singletonFactories缓存中已经有值了 只不过存的是一个工厂的函数式接口
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//此时此刻就会去执行函数式接口的具体实现 也就是AbstractAutowireCapableBeanFactory.getEarlyBeanReference方法
singletonObject = singletonFactory.getObject();
//放入earlySingletonObjects缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
很明显此时已经从singletonFactories缓存中拿到了A对象,那么就可以继续B对象的创建过程了。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 再次从singletonObjects缓存中获取 肯定还是获取不到
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
//将正在创建的对象放到集合中 表示:当前对象正在创建中
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//此处是调用方法入参中的第二个参数 即:lambda表达式
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
//从正在创建的集合中删除
afterSingletonCreation(beanName);
}
if (newSingleton) {
//将当前bean放入singletonObjects缓存中
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
addSingleton(beanName, singletonObject)这个方法正式将B对象放进了singletonObjects缓存中,最后将B对象返回。此时给A对象的b属性也就赋值成功了。
最后A对象回调init方法执行后置处理器等等完成其初始化。行棋至此A B两个对象都已经创建完成。
最后我们通过一个流程图来回顾一下: