栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring IOC & 循环依赖 & 三级缓存

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring IOC & 循环依赖 & 三级缓存

容器初始化

AbstractApplicationContext#refresh方法初始化

    读取bean配置生成BeanDefinition对象
    ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

    根据bean配置BeanDefinition首先创建各种BeanPostProcessor类的单例bean到容器中
    this.registerBeanPostProcessors(beanFactory);

    创建bean配置中的单例bean到容器中
    this.finishBeanFactoryInitialization(beanFactory);

对象注入 获取bean

在this.finishBeanFactoryInitialization(beanFactory)方法中会调用
AbstractBeanFactory#getBean(java.lang.String)方法获取bean

AbstractBeanFactory#doGetBean是真正获取bean的位置

获取缓存中的bean
Object sharedInstance = getSingleton(beanName);
    先在一级缓存singletonObjects中找一级缓存中不存在,再在二级缓存earlySingletonObjects中找二级缓存中不存在,最后在三级缓存singletonFactories中找

从缓存中找到后调用getObjectForBeanInstance获取bean对象

getObjectForBeanInstance方法说明:
如果是ObjectFactory对象,调用getObject方法创建对象返回,否则直接返回对象
循环依赖的时候这里取出一级缓存中的工厂类对象,调用getEarlyBeanReference方法提前加强获取代理对象

注入依赖的bean
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);
				 getBean(dep);
	   }
}

缓存中不存在bean,遍历bean的所有依赖bean(使用@Dependency注解配置)

    registerDependentBean(dep, beanName); 注册到dependentBeanMap,里面存放的是该bean的依赖bean

    getBean(dep); 获取依赖的bean

创建bean
sharedInstance = getSingleton(beanName, new ObjectFactory() {
        @Override
        public Object getObject() throws BeansException {
               return createBean(beanName, mbd, args); 
        }
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
 

DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory)方法说明

    singletonObject = singletonFactory.getObject();
    获取对象,这里就是使用createBean创建beanaddSingleton(beanName, singletonObject);
    添加到一级缓存singletonObjects中以及添加到registeredSingletons中,同时清除其他缓存中的对象,

AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])方法说明

    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    遍历所有InstantiationAwareBeanPostProcessor类型的bean,执行postProcessBeforeInstantiation(Class beanClass, String beanName)方法Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    真正创建bean的位置

AbstractAutowireCapableBeanFactory#doCreateBean方法说明

实例化
instanceWrapper = createBeanInstance(beanName, mbd, args);
添加工厂类对象到三级缓存

判断是否允许提前加强目标bean,允许则添加代理加强bean的工厂类对象到三级缓存中

//判断条件
earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));

//添加工厂类到二级缓存
addSingletonFactory(beanName, new ObjectFactory() {
         @Override
         public Object getObject() throws BeansException {
            return getEarlyBeanReference(beanName, mbd, bean);
         }
});
 
属性注入 
populateBean(beanName, mbd, instanceWrapper);

AbstractAutowireCapableBeanFactory#populateBean方法说明

    遍历InstantiationAwareBeanPostProcessor类型的bean,执行boolean postProcessAfterInstantiation(Object bean, String beanName)方法

    获取所有属性对应的bean

    按名字注入:autowireByName(beanName, mbd, bw, newPvs);
    按类型注入:autowireByType(beanName, mbd, bw, newPvs);

这里只看autowireByName
AbstractAutowireCapableBeanFactory#autowireByName方法说明

    Object bean = getBean(propertyName);获取属性的bean

    registerDependentBean(propertyName, beanName);注册到dependentBeanMap,里面存放的是该bean的依赖bean,注入的属性也类似于依赖

    遍历InstantiationAwareBeanPostProcessor类型的bean,执行postProcessPropertyValues处理bean的属性

    注入各属性的bean到对象中

    applyPropertyValues(beanName, mbd, bw, pvs);
    
初始化bean
if (exposedObject != null) {
		exposedObject = initializeBean(beanName, exposedObject, mbd);
}

这里就是执行代理加强的地方

AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)方法说明

    注入容器相关的属性
    invokeAwareMethods(beanName, bean);

    if (bean instanceof BeanNameAware) {
       ((BeanNameAware) bean).setBeanName(beanName);//注入bean名称
    }
    if (bean instanceof BeanClassLoaderAware) {
       ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader()); //注入类加载器
    }
    if (bean instanceof BeanFactoryAware) {
       ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); //注入容器
    }
    

    前置加强bean

    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    

    遍历BeanPostProcessor类型的对象,执行postProcessBeforeInitialization获取加强bean

    执行初始化方法

    invokeInitMethods(beanName, wrappedBean, mbd);
    

      如果bean实现了InitializingBean接口,调用afterPropertiesSet方法

      如果bean配置了初始化方法(@Bean注解中的initMethod属性),执行该初始化方法

    后置加强bean

    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    

    遍历BeanPostProcessor类型的对象,执行postProcessAfterInitialization获取加强bean

处理循环依赖

处理对象在属性注入之后在初始化的过程加强后又生成代理对象的情况

    获取二级缓存的bean

    Object earlySingletonReference = getSingleton(beanName, false);
    

    如果二级缓存中没有bean,说明没有循环依赖

    这个时候已经通过初始化加强了对象,可以直接返回加强对象

    return exposedObject;
    

    证明没有循环依赖,用反证法:

    ​ 如果有循环依赖,当该bean依赖的对象注入该bean的时候使用getBean获取该bean的时候已经从一级缓存转移到了二级缓存,与条件不符

    二级缓存中有该bean,一定是有循环依赖的

      如果bean在初始化的时候没有加强生成代理对象,则直接使用二级缓存中的代理加强对象

      if (exposedObject == bean) {
        exposedObject = earlySingletonReference;
      }
      

      如果bean在初始化的时候加强生成了代理对象,抛出异常

      else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
      		String[] dependentBeans = getDependentBeans(beanName);
      		Set actualDependentBeans = new linkedHashSet(dependentBeans.length);
      		for (String dependentBean : dependentBeans) {
      			   if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
      							actualDependentBeans.add(dependentBean);
      					}
      		}
      		if (!actualDependentBeans.isEmpty()) {
      				throw new BeanCurrentlyInCreationException(beanName,
      								"Bean with name '" + beanName + "' has been injected into other beans [" +
      								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
      								"] in its raw version as part of a circular reference, but has eventually been " +
      								"wrapped. This means that said other beans do not use the final version of the " +
      								"bean. This is often the result of over-eager type matching - consider using " +
      								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
      		}
      }
      

      为什么有问题:

      ​ 因为存在循环依赖,A依赖B,B依赖A,B注入A使用的代理对象A1,A初始化生成的代理对象A2,这里就有两个对象了

面试题 为什么循环依赖的bean不能在初始化的时候生成代理对象,而使用了工厂类对象

假设A依赖B,B依赖A,

    先创建A,A的工厂类对象放入三级缓存,注入属性BB不存在,创建B,注入属性A从三级缓存中取出A的工厂对象,使用工厂对象创建A的代理对象A1添加A的代理对象A1到B的属性中,创建B完成初始化A,创建A的原始对象的代理对象A2
    这个时候如果使用A1作为最终对象,则会缺失在A2中的加强方法,如果使用A2作为最终对象,则B中的属性A1依然存在,使用时会产生问题
为什么要用三级缓存而不用二级缓存

前提:初始化加强放在属性注入后面
如果存在循环依赖,因为属性注入的时候需要最终对象(而不是原始对象),这个时候被注入的对象需要提前初始化加强
如果缓存中直接存放初始化加强的对象,则违背了前提

源代码 AbstractApplicationContext#refresh
public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				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.
				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();
			}
		}
}
AbstractBeanFactory#doGetBean
protected  T doGetBean(
			final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly)
			throws BeansException {

		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isDebugEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				String nameToLookup = originalBeanName(name);
				if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
			}

			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			try {
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				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);
						getBean(dep);
					}
				}

				// Create bean instance.
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, new ObjectFactory() {
						@Override
						public Object getObject() throws BeansException {
							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;
							}
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
					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, new ObjectFactory() {
							@Override
							public Object getObject() throws BeansException {
								beforePrototypeCreation(beanName);
								try {
									return createBean(beanName, mbd, args);
								}
								finally {
									afterPrototypeCreation(beanName);
								}
							}
						});
						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.
		if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
			try {
				return getTypeConverter().convertIfNecessary(bean, requiredType);
			}
			catch (TypeMismatchException ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}
 
AbstractAutowireCapableBeanFactory#doCreateBean 
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
		Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
		mbd.resolvedTargetType = beanType;

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		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() {
				@Override
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper);
			if (exposedObject != null) {
				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);
			}
		}

		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set actualDependentBeans = new linkedHashSet(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
}


转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号