spring的ioc來解決循環依賴的問題,從AbstractBeanFactory#getBean方法來進行源碼分析,spring的解決循環依賴的原理,能夠從三個本地緩存Map集合進行調解,本篇文章打算從循環依賴的定義來解釋,在結合源碼進行分析。spring
最簡單的例子,spring的循環依賴,就是類A依賴類B,類B依賴類A,他們之間就行成了循環依賴。這是最簡答例子,依據此方案就能夠依賴3個類相互依賴可能致使死循環的情況。看代碼實現:緩存
`app
@Servcie
Class A {
@Autowired
private B b;
}
@Service
Class B {
@Autowired
private A a;
}
複製代碼
IOC容器去加載bean的時候,按照順序去加載,會優先加載beanA而後會注入beanB,發現beanB沒被實例,接下來會加載beanB而後注入beanA,這時候發現beanA沒被實例。致使整個過程造成死循環,程序會一直加載,最終致使內存溢出。spring解決方案,採用三級緩存的實現方案,在容器加載beanB的時候,發現beanB依賴beanA,容器會在加載beanA放入到早期緩存,並把這個早期beanA注入到beanB中,beanB完成實例。beanA也就能夠完成實例化。ide
`源碼分析
/** 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. */
//存放bean工廠對象,用於解決循環依賴
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
複製代碼
咱們直接從AbstractBeanFactory#doGetBean方法開始分析。 `post
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//對bean進行check ,若是bean已經被實例就直接返回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 {
//。。。中間省略細節
// Create bean instance.
//根據bean的做用域去分析
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
//這是建立bean的方法
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, () -> {
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;
}
}
複製代碼
` 上面是獲取bean的過程,先是從緩存中獲取bean,若是沒有會去建立beanui
`this
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//先從最終緩存獲取實例
Object singletonObject = this.singletonObjects.get(beanName);
//判斷beanName對應的bean是否正在建立中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//從早期緩存中獲取
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;
}
複製代碼
上面的源碼中,doGetBean 所調用的方法 getSingleton(String)是一個空殼方法,其 主要邏輯在 getSingleton(String, boolean) 中。該方法邏輯比較簡單,首先從 singletonObjects 緩存中獲取 bean 實例。若未命中,再去 earlySingletonObjects 緩存中獲取原始 bean 實例。若是仍未命中,則從 singletonFactory 緩存中獲取 ObjectFactory 對象,而後再調用 getObject 方法獲取原始 bean 實例的應用, 也就是早期引用。獲取成功後,將該實例放入 earlySingletonObjects 緩存中,並將 ObjectFactory 對象從 singletonFactories 移除。看完這個方法,咱們再來看看 getSingleton(String, ObjectFactory) 方法,這個方法也是在 doGetBean 中被調用的。下面咱們繼續往下跟蹤doCreateBean方法 `spa
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
//將bean實例化,而且包裹BeanWrapper對象中
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final 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");
}
//將bean工廠對象加入到singletonFactories對象早期bean工廠
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//注入屬性bean
populateBean(beanName, mbd, instanceWrapper);
//執行一些初始化參數例如BeanNameAware
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);
}
}
複製代碼
` 在建立bean的過程分爲三個部分,①、建立原始bean實例createBeanInstance,②、添加原始對象工廠對象到singletonFactories,③、注入屬性bean。下面這張圖是摘自別人博客prototype
本篇文章是對整個ioc如何解決循環依賴的,其實本質就是ioc容器加載的核心部分,相應的bean生命週期的核心也能在本篇透析出來。以上就是ioc的講解,本人能力有限,你們相互進步喲。