首頁>技術>

前言

說起Spring中迴圈依賴的解決辦法,相信很多園友們都或多或少的知道一些,但當真的要詳細說明的時候,可能又沒法一下將它講清楚。本文就試著儘自己所能,對此做出一個較詳細的解讀。另,需注意一點,下文中會出現類的例項化跟類的初始化兩個短語,為怕園友迷惑,事先宣告一下,本文的例項化是指剛執行完構造器將一個物件new出來,但還未填充屬性值的狀態,而初始化是指完成了屬性的依賴注入。

1、什麼是迴圈依賴

透過以下一個例子,我們來看下什麼是迴圈依賴:

有兩個類A和B,其程式碼分別如下所示:

/** * 迴圈依賴A * @date: 2020/12/24 * @author weirx * @version 3.0 */public class A {    public B getB() {        return b;    }    public void setB(B b) {        this.b = b;    }    private B b;}/** * 迴圈依賴B * @date: 2020/12/24 * @author weirx * @version 3.0 */public class B {    public A getA() {        return a;    }    public void setA(A a) {        this.a = a;    }    private A a;}

A中有屬性b,B中有屬性a,想回依賴如下圖所示:

迴圈依賴導致了什麼問題?

在學習bean的生命週期時,bean在例項化後要經歷初始化的過程,初始化需要對bean的屬性進行賦值,而A的例項進行初始化的時候,B還沒有沒例項化,導致A的屬性賦值失敗。

2、spring解決方案

瞭解過相關內容的同學,一定知道spring解決迴圈依賴的方案是採用三級快取,sping原始碼中有個重要的類DefaultSingletonBeanRegistry,在這裡面定義了三級快取,如下所示:

    //一級快取    /** Cache of singleton objects: bean name to bean instance. */    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);    //三級快取    /** Cache of singleton factories: bean name to ObjectFactory. */    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);    //二級快取    /** Cache of early singleton objects: bean name to bean instance. */    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

其本質在於bean例項化和初始化分開處理,藉助快取實現了半成品(未經過初始化)的提前暴露

這裡面需要有一個點需要注意下,spring常用的注入方式有set方式和構造器方式,那麼這兩種方式能否解決迴圈依賴的問題呢?

main方法:
import org.springframework.context.support.ClassPathXmlApplicationContext;/** * main * @date: 2020/12/23 * @author weirx * @version 3.0 */public class TestSpring {    public static void main(String[] args) {        ClassPathXmlApplicationContext applicationContext                = new ClassPathXmlApplicationContext("spring-beans.xml");    }}
set方式:
/** * 迴圈依賴A * @date: 2020/12/24 * @author weirx * @version 3.0 */public class A {    public B getB() {        return b;    }    public void setB(B b) {        this.b = b;    }    private B b;}/** * 迴圈依賴B * @date: 2020/12/24 * @author weirx * @version 3.0 */public class B {    public A getA() {        return a;    }    public void setA(A a) {        this.a = a;    }    private A a;}
xml檔案:
        <bean id="a" class="com.demo.A">            <property name="b" ref="b"></property>        </bean>        <bean id="b" class="com.demo.B">            <property name="a" ref="a"></property>        </bean>

執行結果,經測試可以解決,得到的物件是迴圈依賴的:

構造器方式:
/** * 迴圈依賴A * @date: 2020/12/24 * @author weirx * @version 3.0 */public class A {    private B b;    public A(B b) {        this.b = b;    }}/** * 迴圈依賴B * @date: 2020/12/24 * @author weirx * @version 3.0 */public class B {    private A a;    public B(A a) {        this.a = a;    }}
xml配置:
<bean id="a" class="com.demo.A">        <constructor-arg ref="b"></constructor-arg>    </bean>    <bean id="b" class="com.demo.B">        <constructor-arg ref="a"></constructor-arg>    </bean>

結果是不能解決,會得到以下報錯資訊:

十二月 25, 2020 9:38:00 上午 org.springframework.context.support.AbstractApplicationContext refresh警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'a' defined in class path resource [spring-beans.xml]: Cannot resolve reference to bean 'b' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in class path resource [spring-beans.xml]: Cannot resolve reference to bean 'a' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'a' defined in class path resource [spring-beans.xml]: Cannot resolve reference to bean 'b' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in class path resource [spring-beans.xml]: Cannot resolve reference to bean 'a' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:704)    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:196)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1356)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1203)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:556)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:897)    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879)    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551)    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:144)    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:85)    at com.demo.TestSpring.main(TestSpring.java:14)Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in class path resource [spring-beans.xml]: Cannot resolve reference to bean 'a' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:704)    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:196)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1356)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1203)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:556)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)    ... 17 moreCaused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:355)    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:227)    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)    ... 29 moreDisconnected from the target VM, address: '127.0.0.1:60287', transport: 'socket'Process finished with exit code 1
3、原始碼跟蹤跟蹤原始碼過程的流程圖

先扔一張我跟蹤原始碼過程的流程圖:

上圖中有個關鍵點,在spring的原始碼中,通常會看到getBean,doGetBean等方法,在解決迴圈依賴過程中,重要的流程如下圖所示:

程式碼跟蹤開始:

類A和B採用set方式

執行main方法:

/** * main * @date: 2020/12/23 * @author weirx * @version 3.0 */public class TestSpring {    public static void main(String[] args) {        ClassPathXmlApplicationContext applicationContext                = new ClassPathXmlApplicationContext("spring-beans.xml");    }}

跟蹤refresh方法的finishBeanFactoryInitialization方法,直接跟蹤器內部的最後一行程式碼beanFactory.preInstantiateSingletons()

public void preInstantiateSingletons() throws BeansException {        if (logger.isTraceEnabled()) {            logger.trace("Pre-instantiating singletons in " + this);        }        // 獲取bean名稱        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);        // 遍歷例項化所有非延時bean        for (String beanName : beanNames) {            //獲取bean的定義            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);            //bean是否不是抽象&是否單例&是否不是懶載入            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {                //是否是工廠bean                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 {                    //獲取bean                    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();                }            }        }    }
getBean方法

上述程式碼忽略不重要的流程,斷點直接走到了getBean方法:

public Object getBean(String name) throws BeansException {        //真正例項化bean的方法        return doGetBean(name, null, null, false);    }

跟蹤進入doGetBean,兩個關鍵點,檢查已經註冊的快取(getSingleton(beanName))建立bean例項,在下面的程式碼中都有註釋,需要重點關注:

    protected <T> T doGetBean(            String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)            throws BeansException {        String beanName = transformedBeanName(name);        Object bean;        // 檢查已經註冊的快取        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);                        }                    }                }                // 建立bean例項                if (mbd.isSingleton()) {                    //從快取獲取bean例項,此處使用函式式介面(ObjectFactory是函式式介面,當呼叫其預設方法,會執行函式內的createBean)                    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 ScopeNotActiveException(beanName, scopeName, 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;    }

我們分別去看下這兩個關鍵點做了什麼?首先是到快取獲取bean例項getSingleton,此時一定是null,因為還沒有進行例項化:

    @Nullable    protected Object getSingleton(String beanName, boolean allowEarlyReference) {        //檢查一級快取是否存在當前bean的例項        Object singletonObject = this.singletonObjects.get(beanName);        //判斷當前物件在快取是否為null,且是否是當前正在建立的bean        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {            synchronized (this.singletonObjects) {                //從二級快取獲取bean例項                singletonObject = this.earlySingletonObjects.get(beanName);                if (singletonObject == null && allowEarlyReference) {                    //從三級快取獲取bean例項                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);                    if (singletonFactory != null) {                        //執行函式式介面內的方法                        singletonObject = singletonFactory.getObject();                        //新增bean到二級快取                        this.earlySingletonObjects.put(beanName, singletonObject);                        //移除三級快取                        this.singletonFactories.remove(beanName);                    }                }            }        }        return singletonObject;    }

查詢快取不存在該例項,則需要建立例項,建立例項的部分程式碼塊如下,這裡重點關注下getSingletion方法,此處是一個lambda表示式:

                // 建立bean例項                if (mbd.isSingleton()) {                    //從快取獲取bean例項,此處使用函式式介面(ObjectFactory是函式式介面,當呼叫其預設方法,會執行函式內的createBean)                    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);                }

進入getSingleton方法看看,第二個引數ObjectFactory<?>,這個物件是一個函式式介面,當執行器內部的預設方法getObject,則會呼叫之前getSingleton的lambda表示式的內容createBean;下面的方法經過獲取一級快取,發現未取到bean例項,後面經過一些判斷執行了singletonFactory.getObject(),進入createBean階段:

    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {        Assert.notNull(beanName, "Bean name must not be null");        synchronized (this.singletonObjects) {            //從一級快取獲取bean            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 {                    //呼叫ObjectFactory的預設方法,執行createBean                    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;        }    }

進入createBean方法,這裡的主要方法就是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 {            //讓BeanPostProcessors有機會返回一個代理而不是目標bean例項            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 {            //真正建立bean的方法            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);        }    }

作者:麒麟才子原文連結:https://juejin.cn/post/6910723955338772494

14
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 帶你飛之——Dubbo之SPI原始碼閱讀