文章目录
前言
当前网络上有许多文章探讨循环依赖及Spring框架如何解决这一问题,然而,他人的观点毕竟是他人的,因此我想写一篇属于自己的文章,来探讨循环依赖的问题。
一、什么是循环依赖
在Spring框架中,循环依赖指的是当两个或多个Bean之间相互依赖,形成循环引用的情况。这种循环依赖可能会导致Spring容器无法正确地实例化Bean,从而引发应用程序启动失败或运行时异常。
例如图中的情况:A对象中依赖于B,B对象中依赖A。
创建过程如下 :
那么在创建A对象时,需要对A进行实例化,随后对其属性B进行赋值,但是这时候还没有B对象,就需要先创建B对象。
在创建B对象时,需要对B进行实例化,随后对其属性A进行赋值,但是这时候A对象还没有创建完成。
这个时候就形成了一个闭环,这种情况就是循环依赖,如果没有正确处理这种情况,程序就会启动失败或运行时异常。
二、解决思路
从上图中可以看到,形成闭环的最后一步为容器中没有A对象 (蓝色线条
),所以这一步如果不存在,那么就不会存在循环依赖问题。
1、循环依赖分类
在Spring框架中,循环依赖可以分为两种主要类型:
1、构造器注入循环依赖
:当两个或多个Bean通过构造器注入相互依赖时,如果它们之间形成了循环引用,Spring容器在创建这些Bean时可能会陷入死循环,导致应用启动失败或者内存溢出等问题。
2、属性注入循环依赖
:当两个或多个Bean通过属性注入相互依赖时,如果它们之间形成了循环引用,Spring容器会尝试解决这种循环依赖。但是,如果解决不当,可能会导致其中一个Bean的某些属性为null,或者Bean的状态不一致,从而引发运行时错误。
其中,构造器循环依赖不能解决,只能抛出异常,而属性注入循环依赖是可以解决的。
2、对象初始化步骤及对象分类
在spring创建对象的流程图中可以看出,对象初始化分为三步:实例化 、填充属性 、初始化。
那么可以将对象分为两类:
1、完成实例化但未完成初始化
2、完成实例化也完成了初始化
发生循环依赖时,即进行到蓝色线条步骤
的时候,对象A是完成实例化但未完成初始化
的
3、spring是如何解决的
在流程图中看出,B对象是在完成实例化之后立刻对属性A进行赋值,虽然A对象没有完成初始化,但是完成了实例化,所以此时拥有了完成实例化但未完成初始化 的A对象。
此时,将这个半成品的A对象 赋值给B,那么蓝色线条步骤
就不会存在,循环依赖问题也就解决了。
即,实例化与初始化分开进行
。
如果实例化与初始化在必须在一起 时,循环依赖问题就不能得到解决,例如构造器注入循环依赖
。
4、图解
上图中,在对象实例化之后就放入半成品对象A ,在给a属性赋值的时候,把半成品对象A 赋值给a,那么会得到一个成品的B对象 ,那么在回去把成品的B对象 赋值给A对象,那么也就得到了一个成品的A对象。
5、三级缓存
在上一步中已经解决了循环依赖问题,那么又有一个新的问题:spring分别创建了半成品的A、B,成品的A、B。如果放在一个map中,显然比较混乱,那么它们在spring中时怎么存放的。
在spring中,spring的开发者使用三个Map存放我们的Bean对象,这三个也就是我们说的三级缓存。
三个Map位于 DefaultSingletonBeanRegistry 类中
java
/** 一级缓存 */
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);
那么这三个Map有什么区别?
1、区别
Map类型不同 :一级、二级缓存为ConcurrentHashMap,三级缓存为HashMap
容量不同 一级缓存为256,二级缓存为16,三级缓存为16
泛型不同 :三级缓存里边放的是ObjectFactory类型,一级、二级缓存为Object
其中最重要的是泛型的不同
,那么ObjectFactory是什么?
2、ObjectFactory是什么
ObjectFactory:函数式接口,可以将lambda表达式作为参数放到方法的实参中。在方法执行的时候不会执行lambda表达式,只有在调用getObject的时候才会执行lambda表达式。
java
@FunctionalInterface
public interface ObjectFactory<T> {
/**
* Return an instance (possibly shared or independent)
* of the object managed by this factory.
* @return the resulting instance
* @throws BeansException in case of creation errors
*/
T getObject() throws BeansException;
}
三、源码debug
1、spring创建对象过程
spring创建对象过程中重要的六个方法
1、dubug第一步------找到getBean
这个方法是在AbstractApplicationContext
类中,这个方法中包含了创建对象的13个流程,我们看其中最重要的finishBeanFactoryInitialization
java
@Override
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();
}
}
}
在beanFactory中可以找到我们的三级缓存:
在singletonObjects中有五个对象,是容器创建时需要的。
在finishBeanFactoryInitialization方法中,有一些判断和设置可以不看,着重看最后一行beanFactory.preInstantiateSingletons();
java
/**
* Finish the initialization of this context's bean factory,
* initializing all remaining singleton beans.
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
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));
}
// Register a default embedded value resolver if no BeanFactoryPostProcessor
// (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
打开preInstantiateSingletons()
方法:
java
@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);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
可以看到beanDefinitionNames中存放着我们需要创建的对象的集合:a和b。随后开始循环创建
首先经过for循环和一些判断之后,进入到了getBean
中,也就是spring创建对象过程中重要的六个方法的第一个。
2、dubug第二步------getBean与doGetBean
在getBean
中,也就是doGetBean
,是spring创建对象过程中重要的六个方法的第二个。
java
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
打开doGetBean
方法:
java
/**
* Return an instance, which may be shared or independent, of the specified bean.
* @param name the name of the bean to retrieve
* @param requiredType the required type of the bean to retrieve
* @param args arguments to use when creating a bean instance using explicit arguments
* (only applied when creating a new instance as opposed to retrieving an existing one)
* @param typeCheckOnly whether the instance is obtained for a type check,
* not for actual use
* @return an instance of the bean
* @throws BeansException if the bean could not be created
*/
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
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.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 + "'");
}
}
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 (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);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
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);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
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;
}
});
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();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
}
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);
}
});
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 && !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;
}
在getSingleton
中,会先检查在单例缓存中是否有手动注册的单例对象,可以看到,现在结果为空。随后开始创建对象。
随后开始走到如下位置,另一个getSingleton
方法,可以看到第一个参数为beanName,第二个参数就是lambda表达式,这时lambda表达式并不会执行。
打开getSingleton
方法,
java
/**
* Return the (raw) singleton object registered under the given name,
* creating and registering a new one if none registered yet.
* @param beanName the name of the bean
* @param singletonFactory the ObjectFactory to lazily create the singleton
* with, if necessary
* @return the registered singleton object
*/
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.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 {
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) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
可以看到,传递的是一个lambda表达式。
当走到singletonObject = singletonFactory.getObject();
时,才会执行lambda表达式。
也就是执行getObject也就是执行刚刚的lambda表达式,执行lambda表达式中的createBean
,spring创建对象过程中重要的六个方法的第三个。
3、dubug第三步------createBean和doCreateBean
在createBean
方法中,经过一些判断,进入doCreateBean
.spring创建对象过程中重要的六个方法的第四个。
java
/**
* Central method of this class: creates a bean instance,
* populates the bean instance, applies post-processors, etc.
* @see #doCreateBean
*/
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
java
/**
* Actually create the specified bean. Pre-creation processing has already happened
* at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
* <p>Differentiates between default bean instantiation, use of a
* factory method, and autowiring a constructor.
* @param beanName the name of the bean
* @param mbd the merged bean definition for the bean
* @param args explicit arguments to use for constructor or factory method invocation
* @return a new instance of the bean
* @throws BeanCreationException if the bean could not be created
* @see #instantiateBean
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
*/
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) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
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.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
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);
}
}
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<String> 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 " +
"'getBeanNamesForType' 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;
}
doCreateBean
方法中,createBeanInstance
就是创建我们的bean实例的。在createBeanInstance
方法中,使用的是反射来创建对象
4、dubug第四步------createBeanInstance创建对象
在createBeanInstance
方法中,最后一个方法为instantiateBean
进入instantiateBean
,先获取了当前对象的构造器,然后创建对象。
进入instaniate
,点进去instantiateClass
这个方法,可以看到:
return ctor.newInstance(argsWithDefaultValues);
此时,就算是利用反射的方式,来创建出了对象了。
总体流程:
从下图可以看出,已经创建完成了A对象,其中属性b为空。
继续向下,可以看到,执行了addSingletonFactory
方法。
点开addSingletonFactory
方法,可以看到,
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
在三级缓存中放入了map,key为beanName,value是一个lambda表达式。
然后将二级缓存清空,将beanName添加到已注册过的集合中。
java
/**
* Add the given singleton factory for building the specified singleton
* if necessary.
* <p>To be called for eager registration of singletons, e.g. to be able to
* resolve circular references.
* @param beanName the name of the bean
* @param singletonFactory the factory for the singleton object
*/
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
现在我们创建了一个半成品的A对象,并且在三级缓存中加了一条数据
5、dubug第五步------populateBean填充属性
执行了addSingletonFactory
方法之后,就开始对属性赋值,打开populateBean
方法,
java
/**
* Populate the bean instance in the given BeanWrapper with the property values
* from the bean definition.
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @param bw the BeanWrapper with bean instance
*/
@SuppressWarnings("deprecation") // for postProcessPropertyValues
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
经过一些逻辑判断之后,直到最后,执行了applyPropertyValues
方法。
这里就不贴完整代码了,只看关键部分。在applyPropertyValues
方法中,有getName和getValue分别获取属性的名称和值。
获取到的值的类型为RuntimeBeanReference
随后执行
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
进行类型转换
刚刚的属性值为RuntimeBeanReference 类型,随后返回resolveReference(argName, ref);
打开resolveReference
方法
java
/**
* Resolve a reference to another bean in the factory.
*/
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
Class<?> beanType = ref.getBeanType();
if (ref.isToParent()) {
BeanFactory parent = this.beanFactory.getParentBeanFactory();
if (parent == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean " + ref +
" in parent factory: no parent factory available");
}
if (beanType != null) {
bean = parent.getBean(beanType);
}
else {
bean = parent.getBean(String.valueOf(doEvaluate(ref.getBeanName())));
}
}
else {
String resolvedName;
if (beanType != null) {
NamedBeanHolder<?> namedBean = this.beanFactory.resolveNamedBean(beanType);
bean = namedBean.getBeanInstance();
resolvedName = namedBean.getBeanName();
}
else {
resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
bean = this.beanFactory.getBean(resolvedName);
}
this.beanFactory.registerDependentBean(resolvedName, this.beanName);
}
if (bean instanceof NullBean) {
bean = null;
}
return bean;
}
catch (BeansException ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
}
}
随后执行至bean = this.beanFactory.getBean(resolvedName);
开始建造b对象
6、dubug第六步------创建B对象
从上得知,进入getBean
方法后和创建A的流程一致,只不过doGetBean
中的getSingleton
方法实现不同
java
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
这里分别从一、二、三级缓存中获取b对象,如果没有就返回空,随后创建,如果有就返回
此时创建完成一个半成品的B对象,随后将半成品的B对象放入三级缓存
7、dubug第七步------给B对象中的a属性赋值
和dubug第五步 流程一致,执行至bean = this.beanFactory.getBean(resolvedName);
开始建造a对象
8、dubug第八步------创建A对象
创建A对象执行至getSingleton
方法,从一、二、三级缓存中获取A对象
可知一级、二级缓存中没有A对象,那么从三级缓存中取,执行至singletonFactory.getObject()
时,执行上文中存入三级缓存的lambda表达式,即dubug第四步 addSingletonFactory
方法中存入的 () -> getEarlyBeanReference(beanName, mbd, bean)
看一下getEarlyBeanReference
方法
java
/**
* Obtain a reference for early access to the specified bean,
* typically for the purpose of resolving a circular reference.
* @param beanName the name of the bean (for error handling purposes)
* @param mbd the merged bean definition for the bean
* @param bean the raw bean instance
* @return the object to expose as bean reference
*/
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
exposedObject 为暴露对象 ,方法中最后返回的也是exposedObject ,那就就是在exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
中对exposedObject 进行了修改,那么看一下getEarlyBeanReference
方法。
java
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
继续向下执行
java
/**
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
* @param bean the raw bean instance
* @param beanName the name of the bean
* @param cacheKey the cache key for metadata access
* @return a proxy wrapping the bean, or the raw bean instance as-is
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
在这里创建一个代理对象。
也就是getEarlyBeanReference
方法中如果进入if条件就会执行createProxy
但是继续向下dubug,并没有进入if条件,直接返回了exposedObject
随后取出A对象放入二级缓存,删除三级缓存中的a
随后返回至applyPropertyValues
方法给B对象的a属性赋值,也就是dubug第七步的目的。
执行完applyPropertyValues
方法中的bw.setPropertyValues(new MutablePropertyValues(deepCopy));
后,就完成了B对象的a属性赋值。可以看到B中此时有A,但是A中还没有B。
此时赋值完成,B为成品对象,返回至getSingleton
方法,执行addSingleton
方法
将B对象放入一级缓存。
java
/**
* Add the given singleton object to the singleton cache of this factory.
* <p>To be called for eager registration of singletons.
* @param beanName the name of the bean
* @param singletonObject the singleton object
*/
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
9、dubug第九步------给A对象中b属性赋值
随后逐步返回至创建A对象时调用的applyPropertyValues
方法,执行dubug第五步
依旧是bw.setPropertyValues(new MutablePropertyValues(deepCopy));
执行完成之后,就可以看到已经完成了对A对象中b属性赋值
之后再次执行创建A对象时调用的addSingleton
方法,此时一级缓存中多了两个我们创建的对象。
10、dubug第十步------循环创建B
由上文可知,我们创建了A和B对象,但是我们进入到getBean
方法是从preInstantiateSingletons
中循环创建A、B进入的创建A对象,此时我们应该进入下一个循环创建B对象了。
随后在创建B对象的getSingleton
方法中在一级缓存能取到B对象,所以直接返回。
至此,完成A、B对象的创建
2、流程图
这里整理了一个大致流程
四、问题与思考
1、三个类型的map分别存储什么类型的对象
一级缓存:成品对象
二级缓存:半成品对象
三级缓存:lambda表达式
2、三个map在查找对象的时候,是按照什么顺序查找的
先从一级缓存中获取对象,如果没有再从二级缓存中获取,二级缓存中没有再从三级缓存中获取。
3、如果只有一个map,可以解决循环问题吗
可以,只要能存储一个标志位区分开成品和半成品就行,但是太麻烦了。
4、如果只有两个map,可以解决循环问题吗
可以,如果对象的创建过程中不包含 aop(没有代理对象的时候) ,那么一级二级缓存就可以解决循环依赖问题,但是如果包含 aop 的操作,那么没有三级缓存的话,循环依赖问题是解决不了的
5、三级缓存是怎么解决AOP问题的
首先一个容器中只能包含一个同名的对象
对象创建的过程中有可能需要生成代理对象,那么如果程序创建了代理对象,那么调用的时候用的是原始对象还是代理对象呢?要使用代理对象,程序怎么知道该用代理对象呢?
程序是没有办法知道的,所以当出现代理对象的时候,就要用代理对象替换掉原始对象。
那么代理对象的创建时在初始化过程扩展阶段,即debug第八步 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
,而属性赋值在生成代理对象前。
怎么完成替换呢 ? 所以需要在前置过程的时候判断需要生成代理对象。即:
这段代码是在lambda表达式(debug第四步的代码addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
)中调用的,那么为什么要用lambda表达式机制中完成呢?
因为对象在什么时候被暴露出去还是被应用是不能提前确定的,只有在被调用的时候才可以判断是原始对象还是代理对象,使用lambda表达式就类似于回调机制,不暴露的时候不执行,被调用的时候才执行,来判断返回的是代理对象还是原始对象。(该lambda表达式是是从三级缓存中取出key为a时调用的,这时候判断是需要队里对象还是原始对象)