案例:
循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B又依赖于A。如下图:
“依赖”在Spring中有两种情况:
1.构造器循环依赖
2.field属性注入循环依赖
构造器循环依赖
@Service
public class A {
public A(B b) { }
}
@Service
public class B {
public B(A a) {
}
}
此时启动项目会报错
field属性注入循环依赖
@Service
public class A1 {
@Autowired
private B1 b1;
}
@Service
public class B1 {
@Autowired
public A1 a1;
}
此时项目可以正常启动
field属性注入循环依赖(prototype)
@Service
@Scope("prototype")
public class A1 {
@Autowired
private B1 b1;
}
@Service
@Scope("prototype")
public class B1 {
@Autowired
public A1 a1;
}
此时启动项目会报错
结论:
1.基于构造函数的注入,如果有循环依赖,Spring是不能够解决的
2.基于prototype类型的属性注入,如果有循环依赖,Spring是不能够解决的
3.@Service默认是单例的,如果有循环依赖,Spring可以解决
源码解析
SpringBean的加载入口
ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring.xml");
applicationContext.getBean(A.class);
了解:
ClassPathXmlApplicationContext :加载XML配置文件
AnnotationConfigWebApplicationContext : 加载Scan注解
此时第二行已经可以获取到bean示例了,即表示在第一行已经完成了对所有bean的加载
ClassPathXmlApplicationContext 构造方法
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
// 存储spring配置文件到本地
setConfigLocations(configLocations);
if (refresh) {
// spring加载bean的核心方法,刷新spring整个的上下文信息
refresh();
}
}
refresh() 方法代码
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
// 设置BeanFactory的后置处理器
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();.
onRefresh();
registerListeners();
// 初始化所有的no-lazy-init 重要!!!
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
destroyBeans();
cancelRefresh(ex);
throw ex;
} finally {
resetCommonCaches();
}
}
}
obtainFreshBeanFactory 方法:获取刷新Spring上下文的Bean工厂
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
return beanFactory;
}
protected final void refreshBeanFactory() throws BeansException {
if (this.hasBeanFactory()) {
this.destroyBeans();
this.closeBeanFactory();
}
try {
// DefaultListableBeanFactory 重要!!!
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
beanFactory.setSerializationId(this.getId());
this.customizeBeanFactory(beanFactory);
this.loadBeanDefinitions(beanFactory);
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory; }
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}
finishBeanFactoryInitialization 方法代码
此代码是 初始化所有的no-lazy-init 重要!!!
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}.
beanFactory.setTempClassLoader(null);
beanFactory.freezeConfiguration();
// 初始化所有的单例bean
beanFactory.preInstantiateSingletons();
}
preInstantiateSingletons 方法部分代码
作用:初始化所有的单例bean
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
// 实例化的核心代码 即getBean
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
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);
}
}
}
getBean方法:对于所有获取Bean对象是实例,都是用这个getBean方法,这个方法最终调用的是doGetBean(AbstractBeanFactory)方法,这个方法就是所谓的DI(依赖注入)发生的地方。
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
doGetBean 方法实现
首先先了解三个map
/**一级缓存,用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**三级缓存 存放 bean 工厂对象,用于解决循环依赖*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/**二级缓存 存放原始的 bean 对象(尚未填充属性),用于解决循环依赖*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
一级缓存:singletonObjects,存放完全实例化属性赋值完成的Bean,直接可以使用。
二级缓存:earlySingletonObjects,存放早期Bean的引用,尚未属性装配的Bean,提前曝光的单例对象;
三级缓存:singletonFactories,里面存放的是要被实例化的对象的对象工厂
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// 获取单例对象
Object sharedInstance = getSingleton(beanName);
doGetBean 方法中首先根据 getSingleton()方法获取单例对象,但是第一次初始化的时候是没有单例对象的,获取为null。代码会继续向下走。
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
此时会调用createBean()方法去创建一个实例;
createBean 源码
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
...
try {
// 调用此方法
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
catch (BeanCreationException ex) {
throw ex;
}
...
}
AbstractAutowireCapableBeanFactory->doCreateBean 实例化之后,会将bean提早曝光
// 当bean为单例 && 容器配置允许循环依赖 && bean正在创建
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
// getEarlyBeanReference走的是InstantiationAwareBeanPostProcessorAdapter->getEarlyBeanReference方法
// 点进去可以看到其实就是返回自己
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
addSingletonFactory 代码
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
// 将bean加入三级缓存中
this.singletonFactories.put(beanName, singletonFactory);
// 将bean从二级缓存中移除
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
可以看出三级缓存跟二级缓存两个map其实是互斥的
此时A(未设置属性值)的引用已经放入到三级缓存中,此时进行populateBean(A)的时候,因为A中注入了B,则会重新走一遍A所经过的流程,直到populateBean(B),此时B中也注入了A,但是A已经存在于三级缓存中。此时B初始化完成。然后A也会初始化完成
总结
1.所有单例的bean在创建完成之前都会提早曝光。
2.提早曝光就是预先为这个bean创建好一个ObjectFactory。一旦发现是循环依赖。就调用ObjectFactory.getObject返回实例。
3.Spring判断循环依赖的条件是earlySingletonObjects里是否存在这个ObjectFactory.getObject生成的object。(或者另外一个map,三级缓存跟二级缓存map是互斥的)