使用过spring的人,肯定知道spring的IOC,DI。那么在我们使用的过程中,可能会出现比如我一个A类,里面注入了B类,而B类,里面又注入了A类
如下图所示:
@Component
public class DemoA {
@Autowired
DemoB demoB;
public DemoA() {
}
}
@Component
public class DemoB {
@Autowired
DemoA demoA;
public DemoB() {
}
}
后来发现项目是正常启动的。
但是如果我们在构造函数里面去进行循环依赖呢
@Component
public class DemoA {
public DemoA(DemoB demoB) {
}
}
@Component
public class DemoB {
public DemoB(DemoA demoA) {
}
}
启动时就会报循环引用的问题
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoA' defined in file [/Users/nanjunbo/Documents/Ideaproject/demoSpring/target/classes/demoIoc/DemoA.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoB' defined in file [/Users/nanjunbo/Documents/Ideaproject/demoSpring/target/classes/demoIoc/DemoB.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'demoA': Requested bean is currently in creation: Is there an unresolvable circular reference?
那这到底是为什么呢?这里就需要知道spring创建bean的时候到底做了什么。
1.首先我们需要知道bean到底是什么?根据spring官方文档的描述,bean是一个由Spring IoC容器实例化、组装和管理的对象。那么原生java对象,跟你用spring来创建一个bean到底有什么区别。其实在创建bean的过程中,对java的原生对做了一系列的处理,扩展。这个就是bean的生命周期。
现在我们从代码看看spring的生命周期。
先看一下测试类:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext abstractApplicationContext = new AnnotationConfigApplicationContext();
abstractApplicationContext.register(DemoConfig.class);
abstractApplicationContext.refresh();
System.out.println(abstractApplicationContext.getBean("demoA"));
}
}
可以看到将测试的配置文件注册进容器中,然后刷新容器,就可以获取bean了。
那refresh到底做了什么呢?
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//使用对象锁,对spring容器的refresh跟destroy进行加锁
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//准备刷新容器前的环境
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//对beanFactory进行赋值
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//提供一个修改beanFactory的入口
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//同样是对beanFactory进行修改
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//注册bean创建时的拦截器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//初始化MessageSource
initMessageSource();
// Initialize event multicaster for this context.
//初始化事件的上下文广播
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//空方法,可以自己定义想处理什么
onRefresh();
// Check for listener beans and register them.
//注册监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//(重要)完成bean的初始换
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
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 beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
//把非RootBeanDefinition的merge成RootBeanDefinition
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//判断是否需要实例化bean
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
//获取factoryBean
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean> factory = (FactoryBean>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction)
((SmartFactoryBean>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
//获取普通Bean(核心方法)
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction
然后主要看doGetBean的方法,然后有一段doCreateBean的方法。
初始化bean的时候,将其放入singletonFactories中,然后调用populateBean方法,来注入属性,如果这时候发生了依赖,比如文章开头的示例,初始化A的时候,注入了B,然后再初始化B,发现又注入了A。这时候初始化B,然后调用populateBean方法时,然后又去getBean(A),去getBean的时候,从singletonFactories中获取,然后就发现了有A的存在,不用再去实例化A了
这里只是大概写了一下,spring的源码太多了,太吊了。只要对大概的流程知道就行了。每一句每一句分析需要消耗大量的时间,不过对个人的成长很有用