循环依赖问题,直接代码问题如下
@Service("clientServices")
public class ClientServices {
@Autowired
private UserServices userServices;
public ClientServices() {
System.out.println("ClientServices Constructed");
}
}
@Service("userServices")
public class UserServices {
@Autowired
private ClientServices clientServices;
public UserServices() {
System.out.println("UserServices Constructed");
}
}
分析: ClientServices中依赖于UserServices作为其类的属性,UserServices也依赖于ClientServices作为其类的属性,如何解决这种循环依赖并且能够顺利的在IoC容器中实例化对应的bean呢?
解决关键点: 在首次创建其中一个bean A时,如果发现存在循环依赖,并且Spring开启循环依赖,则记录其中一个bean A正在创建中(还未完成bean A的生命周期)、此时调用createBean去实例化需要依赖的另外一个bean B。在第二个bean B被实例化时,也会发现自己依赖的属性A也还没有创建(单例池中取不到A),故而去实例化要依赖的bean A,于是回到了最初实例化bean A的起点,但是这一次创建,Spring发现A依赖的属性B正在被创建,则直接会从earlySingletonObjects获取并返回即取到正在创建中但是还未完成完整bean生命周期的bean B、于是bean A成功获取到其所需要的属性 B,顺利完全其生命周期,成为一个Spring bean;之后,bean B依赖的属性A可以从singletonObjects(单例池)中取到,在完成其完整bean生命周期后,也成为一个Spring bean。从而得到解决。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 验证bean的名字是否非法
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
/* getSingleton方法解析:
* 这里是第一次调用getSingleton方法,下面spring还会调用一次
* 但是两次调用的方法非同一个方法(方法重载)
* 第一次getSingleton(beanName)是循环依赖最重要的方法
* 具体内容:
* 1、spring去单例池获取这个bean,单例池是一个Map
* 2、如果对象被创建了则直接从Map中获取并返回
* 理解:doGetBean方法不仅仅是用来第一次获取bean,而是创建bean和getBean方法共用的一个方法
* 循环引用需要在创建bean的时候去获取被引用的类,而被引用的类此时还没有被创建,
* 则会调用creatBean来创建这个bean,创建这个bean时则会检查是否已经被实例化
* 对象:类被实例化后
* bean:经过一系列bean生命周期后,放入单例池中的对象
* 回到循环引用,首先spring扫描到一个需要被实例化的类A,于是创建a:A a = new A();
* new A的过程中Spring会去调用getBean("a");此时,get结果肯定为空。
* 原因:(并非因为getBean是从容器中获取,所以为空)
* 第一次调用getSingleton(beanName)方法后,spring判断这个类没有创建
* 然后Spring第二次调用getSingleton(重载方法),在里面记录了一下自己已经开始实例这个类了。
* 面试:说明spring实例化一个对象底层用的是反射;spring实例化一个对象的过程非常复杂,需要推断构造方法、单例原型、懒加载等.
* 对象在完成spring的bean生命周期的过程中,会去判断IoC容器是否允许循环引用(spring默认支持循环引用)
* 如果允许循环依赖,spring把这个对象的beanDefinition暂存到Map中(并非单例池的singletonObjects)
* 另外还有存放临时对象的earlySingletonObjects。
* 3 Map:
* singletonObjects(存放单例bean):缓存创建好的bean,方便Coder getBean
* singletonFactories(存放临时对象(没有 完整Spring-Bean生命周期的对象))
* earlySingletonObjects(同上)
* 后面两个Map支撑循环引用。
* 当进行对象 a的属性填充时,发现a依赖了B类,然后spring判断这个B类到底有没有bean在IoC容器中
* 这里的判断是从第一个map:singletonObjects中 getBean。
* 假设没有,则spring调用createBean,于是重复A的过程,在创建B b时,调用getBean("b")
* 此时get结果必然为null,而此时第一次调用完getSingleton后进而调用第二次getSingleton
* 第二次调用时会在set集合中记录B b正在创建(此时,set集合中已有至少2条记录a和b正在被创建)
* 如果为空,则B b = new B();接着完善b的bean生命周期,同样会判断是否允许循环依赖,允许则放到第二个map:singletonFactories
* 此时singletonFactories中已经存在a和b,紧接着对b的属性进行填充时发觉需要依赖A,于是就去第一个Map中去寻找a(此时a还只是对象非bean)
* 故而getBean("a")为null,所以 b判定a还没有创建,故而去创建了a,事件线又回到了起点(循环)
* 但是,这次会判断a是否等于null,如果为空,则进而判断a是否正在创建中(set集合记录了a)
* 如果a正在被创建(被set记录了),则直接从第二个map:earlySingletonObjects中取出a并返回,所以这一次就不等于空了
* 于是乎B就可以自动注入a了,但a还只是一个对象,a这个对象依赖的b还没有注入,当b对象注入完成a后,把b的bean生命周期走完,存到IoC容器中
* 此时,返回到a注入b的地方,得到的返回对象也是一个bean(b),a故而能够注入b了,进而a也放入到IoC容器中进行管理。
* */
// 第一次get不到
// sharedInstance 为null
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 + "'");
}
}
// 处理FacotryBean的情况
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 此处针对原型bean??
// 判断这个原型bean是不是在创建过程中
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
// 检查bean是否存在于父级IoC容器中
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// 当没找到这个bean时,获取父级容器中beanFactory利用beanName调用父级beanFactory的doGetBean方法
// beanName:符合系统规范的bean名,name指最原始的名
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
// 如果不仅仅是类型检查,则利用beanName去标记当前正在创建的bean
// 当仅仅是进行类型检查时,则不会记录当前正在创建的bean
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// 获取合并的beanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查beanDefinition是否为抽象类
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// 获取@DependsOn注解的依赖
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
// 优先创建依赖的类,如果此时发生循环依赖,则会报错
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 将依赖关系注册到集合中
registerDependentBean(dep, beanName);
try {
// 递归调用getBean方法获取当前所依赖的bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
// 单例bean
if (mbd.isSingleton()) {
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;
}
});
// 处理FactoryBean的情况
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 当beanDefinition是原型(多例)对象时,直接调用createBean方法创建实例
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
// 原型bean的循环依赖检测(记录正在创建ing)
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
// 处理FactoryBean的情况
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
// 获取该bean的生命周期范围@Scope,在refesh()方法中的postProcessBeanFactory方法进行自定义生命周期注册
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
// 处理FactoryBean的情况
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
// 最后一步检查: 检查指定类型与实际得到的bean类型是否存在出入,如果是,则尝试进行转换
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}