講解內(nèi)容:
- spring的循環(huán)依賴---屬性注入--自動(dòng)注入
- spring bean的生命周期
- spring bean實(shí)例化的過程
- spring循環(huán)依賴
講解模式
- 打斷點(diǎn),一步一步走過spring bean循環(huán)依賴解決過程茬腿。由于spring 創(chuàng)建bean過程繁雜智厌,重要的代碼會(huì)講解蝇棉,不重要的忽略谚殊。自動(dòng)注入也是個(gè)重點(diǎn)婉陷,后面文章會(huì)再次講解到恬砂。
- 本筆記是個(gè)人學(xué)習(xí)子路老師的課程所做的咧纠,有興趣的可以去看看他的課,講的更好
帶著問題學(xué)習(xí)
問題1:spring當(dāng)中的循環(huán)依賴如何解決的
問題2:spring當(dāng)中怎么支持循環(huán)依賴的
回答:
spring中的AbstractAutowireBeanFactory類里面有個(gè)變量allowCircularRefrence=true這是設(shè)置是否支持循環(huán)依賴的參數(shù)泻骤,在么個(gè)bean創(chuàng)建的過程中晤柄,都會(huì)進(jìn)行判斷厌衔。可以通過啟動(dòng)類中的
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
AbstractAutowireCapableBeanFactory acb = ac.getDefaultListableBeanFactory();
acb.setAllowCircularReferences(false);
ac.register(Test.class);
ac.refresh();
ac.getBean(IndexService.class).getService();
}
或者修改源碼,在AnnotationConfigApplicationContext類中直接
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
setAllowCircularReference(false);
register(annotatedClasses);
refresh();
}
問題3:如何證明spring默認(rèn)支持循環(huán)依賴(源碼細(xì)節(jié))
問題4:對(duì)spring源碼有什么了解嗎售担?(可以回答一個(gè)IOC或者AOP即可)
問題5:對(duì)spring源碼深入研究,可以進(jìn)行二次擴(kuò)展嗎氢伟?(直接繼承BeanFactoryPostProcess類)
public class ZbBeanFactoryPostProcess implements BeanFactoryPostProcessor {
//這里的factory中調(diào)用的所有對(duì)象都是二級(jí)緩存中的酷宵,在加載到三級(jí)緩存中之前會(huì)調(diào)用用戶自己寫的擴(kuò)展類。
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
// GenericBeanDefinition是BeanDefinition的子類器虾,子類具有更多的實(shí)現(xiàn)讯嫂,rootBeanDefinition也是BeanDefinition的子類
GenericBeanDefinition userService = (GenericBeanDefinition)configurableListableBeanFactory.getBeanDefinition("userService");
userService.setScope("");
userService.setBeanClassName("XXX");
}
}
問題6:如何關(guān)閉單例循環(huán)依賴
啟動(dòng)類中AnnotationConfigApplicationContext.java的構(gòu)造方法中添加setAllowCircularReference(false即可)
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
setAllowCircularReference(false);
register(annotatedClasses);
refresh();
}
問題7:@Autowired和@Source有什么不一樣
回答:在bea初始化的時(shí)候bean注入各種屬性的時(shí)候,處理他們的后置處理器不一樣
問題:如何解決循環(huán)依賴>>>依賴注入功能>>>初始化完成依賴注入>{
1兆沙、初始化bean ------ b
}
問題:循環(huán)依賴的過程
回答:
getBean() ------index object --------注入U(xiǎn)serService-----getBean(UserService) ---從容器中拿(三級(jí)緩存)-----拿不到----判斷是否需要第三個(gè)緩存中拿------開始new Userservice-----object UserService --------注入index----從容器中拿getBean(Index)-----index不等于nulll,注入半成品index---創(chuàng)建userservice .
問題:spring bean聲明周期如何完成依賴注入的呢欧芽?
問題:spring bean的產(chǎn)生過程,bean是如何產(chǎn)生的
現(xiàn)有class--beanDefinition(類)------object(bean)
spring懶加載葛圃,在類上面直接使用注解@Lazy(true)千扔,表明這個(gè)類在初始化的時(shí)候不加載,到用到的時(shí)候才會(huì)去加載
注意:
bean----------spring bean
java對(duì)象-----對(duì)象
spring bean創(chuàng)建過程簡(jiǎn)單概述
先過過眼装悲,具體內(nèi)容后面詳細(xì)講解昏鹃,這里有個(gè)大概印象
getBean() ------index object --------注入U(xiǎn)serService-----getBean(UserService) ---從容器中拿(三級(jí)緩存)-----拿不到----判斷是否需要第三個(gè)緩存中拿------開始new Userservice-----object UserService --------注入index----從容器中拿getBean(Index)-----index不等于nulll,注入半成品index---創(chuàng)建userservice .
文字描述
- 實(shí)例化一個(gè)ApplicationContext的對(duì)象;
- 調(diào)用bean工廠后置處理器完成掃描诀诊;
- 循環(huán)解析掃描出來(lái)的類信息洞渤;
- 實(shí)例化一個(gè)BeanDefinition對(duì)象來(lái)存儲(chǔ)解析出來(lái)的信息;
- 把實(shí)例化好的beanDefinition對(duì)象put到beanDefinitionMap當(dāng)中緩存起來(lái)属瓣,以便后面實(shí)例化bean载迄;
- 再次調(diào)用bean工廠后置處理器;
- 當(dāng)然spring還會(huì)干很多事情抡蛙,比如國(guó)際化护昧,比如注冊(cè)BeanPostProcessor等等,如果我們只關(guān)心如何實(shí)例化一個(gè)bean的話那么這一步就是spring調(diào)用finishBeanFactoryInitialization方法來(lái)實(shí)例化單例的bean粗截,實(shí)例化之前spring要做驗(yàn)證惋耙,需要遍歷所有掃描出來(lái)的類,依次判斷這個(gè)bean是否Lazy,是否prototype绽榛,是否abstract等等湿酸;
- 如果驗(yàn)證完成spring在實(shí)例化一個(gè)bean之前需要推斷構(gòu)造方法,因?yàn)閟pring實(shí)例化對(duì)象是通過構(gòu)造方法反射灭美,故而需要知道用哪個(gè)構(gòu)造方法推溃;
- 推斷完構(gòu)造方法之后spring調(diào)用構(gòu)造方法反射實(shí)例化一個(gè)對(duì)象;注意我這里說(shuō)的是對(duì)象届腐、對(duì)象铁坎、對(duì)象;這個(gè)時(shí)候?qū)ο笠呀?jīng)實(shí)例化出來(lái)了犁苏,但是并不是一個(gè)完整的bean硬萍,最簡(jiǎn)單的體現(xiàn)是這個(gè)時(shí)候?qū)嵗鰜?lái)的對(duì)象屬性是沒有注入,所以不是一個(gè)完整的bean傀顾;
- spring處理合并后的beanDefinition(合并襟铭?是spring當(dāng)中非常重要的一塊內(nèi)容,后面的文章我會(huì)分析)短曾;
- 判斷是否支持循環(huán)依賴寒砖,如果支持則提前把一個(gè)工廠存入singletonFactories——map;
- 判斷是否需要完成屬性注入
- 如果需要完成屬性注入嫉拐,則開始注入屬性
- 判斷bean的類型回調(diào)Aware接口
- 調(diào)用生命周期回調(diào)方法
- 如果需要代理則完成代理
- put到單例池——bean完成——存在spring容器當(dāng)中
對(duì)象的創(chuàng)建過程
1哩都、scan掃描類
2、parse解析婉徘,利用for循環(huán)對(duì)所有遍歷的類進(jìn)行解析,設(shè)置類的名稱漠嵌,父類,單例還是原型等等盖呼。
for (){
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClassName("XXX");
genericBeanDefinition.setBeanClass("XXXX.class");
genericBeanDefinition.setScope("prototytype"
.......
//放入到一級(jí)緩存中
map.put("XXXX");
list<String>.add(xxxx)
}
3儒鹿、調(diào)用擴(kuò)展,
遍歷map validate校驗(yàn)類中是否符合各種規(guī)則
然后符合就直接new了几晤。
開啟spring循環(huán)依賴講解
循環(huán)依賴樣例
UserService.java
package test.service;/**
* Created by zhanbei on 2020/12/6.
*/
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class UserService {
@Autowired
private IndexService indexService;
public UserService(){
System.out.println("UserService start");
}
}
IndexService.java
package test.service;/**
* Created by zhanbei on 2020/12/6.
*/
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class IndexService {
@Autowired
private UserService userService;
public IndexService(){
System.out.println("IndexServicde started");
}
public String getService(){
return "IndexService";
}
}
bean的實(shí)例化生命周期
1约炎、啟動(dòng)類中調(diào)用的AnnotationConfigApplicationContext類
@Lazy(true)
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Test.class);
ac.getBean(IndexService.class).getService();
}
}
在這里可以做很多事情,可以關(guān)閉循環(huán)依賴等等蟹瘾,只要在ac.refresh()方法執(zhí)行之前圾浅,可以修改很多spring內(nèi)部的東西。如下
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
AbstractAutowireCapableBeanFactory acb = ac.getDefaultListableBeanFactory();
//可以在這里關(guān)閉循環(huán)依賴
acb.setAllowCircularReferences(false);
ac.register(Test.class);
ac.refresh();
ac.getBean(IndexService.class).getService();
}
2憾朴、AnnotationConfigApplicationContext類中主要代碼狸捕,主要構(gòu)件bean生命周期的是refresh()方法
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
//也可以在這關(guān)閉循環(huán)依賴,這里是我個(gè)人手動(dòng)修改的spring源碼
setAllowCircularReference(false);
register(annotatedClasses);
refresh();
}
3众雷、refresh方法里才是整個(gè)bean生命周期開始的地方灸拍,準(zhǔn)確的開始地方做祝,后面會(huì)講解(refresh在spring-context-5.1.13.RELEASE.jar.org.springframework.context.support.AbstractApplicationContext.class中)
@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.
//調(diào)用finishBeanFactoryInitialization方法實(shí)例化所有掃描出來(lái)的類
//spring在AbstractApplicationContext#finishBeanFactoryInitialization方法中完成了bean的實(shí)例化。這點(diǎn)需要記住
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();
}
}
}
3.1株搔、finishBeanFactoryInitialization方法中調(diào)用preInstantiateSingletons初始化掃描出來(lái)的類剖淀。
**
* Finish the initialization of this context's bean factory,
* initializing all remaining singleton beans.
*/
rotected 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 bean post-processor
// (such as a PropertyPlaceholderConfigurer 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();
}
3.2、preInstantiateSingletons方法會(huì)經(jīng)過一系列的判斷之后纤房,調(diào)用getBean方法區(qū)實(shí)例化掃描出來(lái)的類
preInstantiateSingletons位于(spring-beans-5.1.13.RELEASE.jar.org.springframework.beans.factory.support.DefaultListableBeanFactory.class)
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("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) {
final 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) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
3.3、getBean僅為一個(gè)空殼翻诉,調(diào)用了doGetBean方法(代碼較長(zhǎng)炮姨,大致過一樣即可,下面會(huì)繼續(xù)針對(duì)這個(gè)有詳細(xì)講解)
public AbstractBeanFactory() {
}
public AbstractBeanFactory(@Nullable BeanFactory parentBeanFactory) {
this.parentBeanFactory = parentBeanFactory;
}
public Object getBean(String name) throws BeansException {
return this.doGetBean(name, (Class)null, (Object[])null, false);
}
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return this.doGetBean(name, requiredType, (Object[])null, false);
}
public Object getBean(String name, Object... args) throws BeansException {
return this.doGetBean(name, (Class)null, args, false);
}
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args) throws BeansException {
return this.doGetBean(name, requiredType, args, false);
}
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly
String beanName = this.transformedBeanName(name);
Object sharedInstance = this.getSingleton(beanName);
Object bean;
if(sharedInstance != null && args == null) {
if(this.logger.isTraceEnabled()) {
if(this.isSingletonCurrentlyInCreation(beanName)) {
this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not
} else {
this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
if(this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = this.getParentBeanFactory();
if(parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
String nameToLookup = this.originalBeanName(name);
if(parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckO
}
if(args != null) {
return parentBeanFactory.getBean(nameToLookup, args);
}
if(requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
return parentBeanFactory.getBean(nameToLookup);
}
if(!typeCheckOnly) {
this.markBeanAsCreated(beanName);
}
try {
RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
this.checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
String[] var11;
if(dependsOn != null) {
var11 = dependsOn;
int var12 = dependsOn.length;
for(int var13 = 0; var13 < var12; ++var13) {
String dep = var11[var13];
if(this.isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on r
}
this.registerDependentBean(dep, beanName);
try {
this.getBean(dep);
} catch (NoSuchBeanDefinitionException var24) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' de
}
}
}
if(mbd.isSingleton()) {
sharedInstance = this.getSingleton(beanName, () -> {
try {
return this.createBean(beanName, mbd, args);
} catch (BeansException var5) {
this.destroySingleton(beanName);
throw var5;
}
});
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if(mbd.isPrototype()) {
var11 = null;
Object prototypeInstance;
try {
this.beforePrototypeCreation(beanName);
prototypeInstance = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
}
bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
String scopeName = mbd.getScope();
Scope 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, () -> {
this.beforePrototypeCreation(beanName);
Object var4;
try {
var4 = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
}
return var4;
});
bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} catch (IllegalStateException var23) {
throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current
}
}
} catch (BeansException var26) {
this.cleanupAfterBeanCreationFailure(beanName);
throw var26;
}
}
if(requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = this.getTypeConverter().convertIfNecessary(bean, requiredType);
if(convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
} else {
return convertedBean;
}
} catch (TypeMismatchException var25) {
if(this.logger.isTraceEnabled()) {
this.logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualified
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
} else {
return bean;
}
}
3.4碰煌、refresh()方法中在經(jīng)過一堆的校驗(yàn)之后舒岸,開始調(diào)用createBean創(chuàng)建bean
()createBean位于org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.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.isDebugEnabled()) {
logger.debug("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.isDebugEnabled()) {
logger.debug("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);
}
}
doGetBean方法內(nèi)容很多,這個(gè)方法非常重要芦圾,不僅僅針對(duì)循環(huán)依賴蛾派。甚至整個(gè)springbean生命周期也有舉足輕重的地位,下面將會(huì)細(xì)致講解
package test.service;
/**
* Created by zhanbei on 2020/12/6.
*/
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @ClassName UserService
* @Description TODO
* @Author zhanbei
* @Date 2020/12/6 21:41
* @Version 1.0
**/
@
Component
public class UserService {@
Autowired
private IndexService indexService;
public UserService() {
System.out.println("UserService start");
}
protected < T > T doGetBean(final String name, @Nullable final Class < T > requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//這個(gè)方法非常重要,但是和筆者今天要分析的循環(huán)依賴沒什么很大的關(guān)系//讀者可以簡(jiǎn)單的認(rèn)為就是對(duì)beanName做一個(gè)校驗(yàn)特殊字符串的功能//我會(huì)在下次更新博客的時(shí)候重點(diǎn)討論這個(gè)方法
//transformedBeanName(name)這里的name就是bean的名字
final String beanName = transformedBeanName(name);
//定義了一個(gè)對(duì)象个少,服存將來(lái)返回出來(lái)的bean
Object bean;
// Eagerly check singleton cache for manu ally registered singletons./**
/**注意這是第一次調(diào)用getSingleton方法洪乍,下面spring還會(huì)調(diào)用一次
* 但是兩次調(diào)用的不是同一個(gè)方法;屬于方法重載
* 第一次getSingleton(beanName) 也是循環(huán)依賴最重要的方法
* 關(guān)于getSingleton(beanName) 具體代碼分析可以參考筆者后面的分析
*于循環(huán)弓|用需要在創(chuàng)建bean的過程中去獲取被引用的那個(gè)類
*而被弓用的這個(gè)類如果沒有創(chuàng)建,則會(huì)調(diào)用createBean來(lái)創(chuàng)建這個(gè)bean
*在創(chuàng)建這個(gè)被引用的bean的過程中會(huì)判斷這個(gè)bean的對(duì)象有沒有實(shí)例化
* bean的對(duì)象?什么意思呢?
*為了方便閱讀,讀者-定記住兩個(gè)概念; 什么是bean,什么是對(duì)象
*筆者以為-個(gè)對(duì)象和bean是有區(qū)別的
*對(duì)象:只要類被實(shí)例化就可以稱為對(duì)象
* bean:先得是一個(gè)對(duì)象, 然后這個(gè)對(duì)象需要經(jīng)歷一系列的bean生 命周期
*后把這個(gè)對(duì)象put到單例池才能算一個(gè)bean
*讀者千萬(wàn)注意,筆者下文中如果寫到bean和寫到對(duì)象不是隨意寫的是和這里的解釋有關(guān)系的;重點(diǎn)-定要注意; -定;一定; 訖就是spring先new-個(gè)對(duì)象,繼而對(duì)這個(gè)對(duì)象進(jìn)行生命周期回調(diào)
*接著對(duì)這個(gè)對(duì)象進(jìn)行屬性填流夜焦,也是大家說(shuō)的自動(dòng)注入
*然后在進(jìn)行AOP判斷等等;這一些操作簡(jiǎn)稱---spring生 命周期.
*所以一個(gè)bean是一個(gè)經(jīng)歷了spring周期的對(duì)象壳澳,和一個(gè)對(duì)象有區(qū)別
*回到前面說(shuō)的循環(huán)引用,首先spring掃描到一 個(gè) 要被實(shí)例化的類A
* 于是spring就去創(chuàng)建A; A=new A-a;new A的過程會(huì)調(diào)用getBean("a"));
*所謂的getBean方法--核心也就是筆者現(xiàn)在寫注釋的這個(gè)getSingleton(beanName)
*所謂的getBean方法-核心也就是筆者現(xiàn)在寫注釋的這個(gè)getSingleton(beanName)
*這個(gè)時(shí)候get出來(lái)肯定為空?為什么是空呢?我寫這么多注釋就是為了解釋這個(gè)問題
*可能有的讀者會(huì)認(rèn)為getBean就是去容器中獲取,所以肯定為空,實(shí)不然接著往下看
*如果getA等于空; spring就會(huì)實(shí)例化A;也就是上面的new A
*但是在實(shí)例化A的時(shí)候會(huì)再次調(diào)用一下
* getSingleton(String beanName, ObjectFactory<?> singletonFactory)*筆者上面說(shuō)過現(xiàn)在寫的注釋給getSingleton(beanName)
*也即是第- -次調(diào)用getSingleton(beanName)
*實(shí)例化一共會(huì)調(diào)用兩次getSingleton方法; 但是是重載
*第二次調(diào)用getSingleton方法的時(shí)候spring會(huì)在一 個(gè)set集合當(dāng)中記錄一 下這個(gè)類正在被創(chuàng)建
*這個(gè)定要記住, 在調(diào)用完成第一次getSingleton完成之后* spring判讀這個(gè)類沒有創(chuàng)建茫经, 然后調(diào)用第二 次getSingleton
*在第二次getSingleton里面記錄了一下自己己經(jīng)開始實(shí)例化這個(gè)類*這是循環(huán)依賴做的最牛逼的地方巷波,兩次getSingleton的調(diào)用
*也是回答面試時(shí)候關(guān)于循環(huán)依賴必須要回答道的地方; .*要說(shuō)明的spring實(shí)例化一 個(gè)對(duì)象底層用的是反射;
*spring實(shí)例化一個(gè)對(duì)象的過程非常復(fù)雜, 要推斷構(gòu)造方等等;
*這里筆者先不討論這個(gè)過程,以后有機(jī)會(huì)更新-下
*讀者可以理解spring直接通過new關(guān)鍵字來(lái)實(shí)例化一個(gè)對(duì)象
*但是這個(gè)時(shí)候?qū)ο骯僅僅是一 個(gè)對(duì)象,還不是一 個(gè)完整的bean
*接著讓這個(gè)對(duì)象完成spring的bean的生命周期
*過程中spring會(huì)判斷容器是否允許循環(huán)弓用卸伞,判斷循環(huán)引用的代碼筆者下面會(huì)分析
*前面說(shuō)過spring默認(rèn)是支持循環(huán)引|用的, 筆者后面解析這個(gè)判斷的源碼也是spring默認(rèn)支持循環(huán)引|用的證據(jù)
*如果允許循環(huán)依賴抹镊,spring會(huì)把這 個(gè)對(duì)象(還不是bean)臨時(shí)存起來(lái),放到一個(gè)map當(dāng)中
*注意這個(gè)map和單例池是兩個(gè)map,在spring源碼中單例池的map叫做singletonObjects
*而這個(gè)存放臨時(shí)對(duì)象的map叫做singletonFactories
*當(dāng)然spring還有一個(gè)存放臨時(shí)對(duì)象的map叫做earlySingletonObjects*所以一共是三個(gè)map,有些博客或者書籍人也叫做三級(jí)緩存
*為什么需要三個(gè)map呢?先來(lái)了解這三個(gè)map到底都緩存了什么
*第一個(gè)map singletonObjects存放的單例的bean
*第二個(gè)map singletonFactories存放的臨時(shí)對(duì)象(沒有完整springBean生命周期的對(duì)象)
*第三個(gè)map earlySingletonObjects存放的臨時(shí)對(duì)象(沒有完整springBean生命周期的對(duì)象)
*筆者為了讓大家不懵逼這里吧第二個(gè)和第三個(gè)map功能寫成了一模一樣
*實(shí)第二個(gè)和第三個(gè)map會(huì)有不一樣的地方,但這里不方便展開講荤傲,下文分析*讀者姑且認(rèn)為這兩個(gè)map是一樣的
*第一個(gè)map主要為了直接緩存創(chuàng)建好的bean;方便程員去getBean;很好理解*第二個(gè)和第三個(gè)主要為了循環(huán)引用;為什么為了方便循環(huán)引用垮耳,接著往下看
*把對(duì)象a緩存到第二個(gè)map之后, 會(huì)接著完善生命周期;
*當(dāng)然spring bean的生命周期很有很多步驟;本文先懷詳細(xì)討論;
*后面的博客者再更新;
*當(dāng)進(jìn)行到對(duì)象a的屬性填充的這一周期的時(shí)候弃酌,發(fā)覺a依賴了一個(gè)B類
*所以spring就會(huì)去判斷這個(gè)B類到底有沒有bean在容器當(dāng)中
*這里的判斷就是從第一個(gè)map即單例池當(dāng)中去拿一 個(gè)bean
*后面我會(huì)通過源碼來(lái)證明是從第-個(gè)map中拿一個(gè)bean的
*假設(shè)沒有氨菇,那么spring會(huì)先去調(diào)用createBean創(chuàng)建這 個(gè)bean
*于是又回到和創(chuàng)建A-樣的流程,在創(chuàng)建B的時(shí)候同樣也會(huì)去getBean("B");* getBean核心也就是筆者現(xiàn)在寫注釋的這個(gè)getSingleton(beanName)方法
*下面我重申一下:因?yàn)槭侵攸c(diǎn)
*這個(gè)時(shí)候get出來(lái)肯定為空?為什么是空呢?我寫這么多注釋就是為了解釋這個(gè)問題?
*可能有的讀者會(huì)認(rèn)為qetBean就是去容器中獲取:
*可能有的讀者會(huì)認(rèn)為getBean就是去容器中獲取;
*所以肯定為空妓湘,期不然查蓉,接著往下看; .
*第一 -次調(diào)用完getSingleton完成之后會(huì)調(diào)用第二次getSingleton
*第二次調(diào)用getSingleton同樣會(huì)在set集合當(dāng)中去記錄B正在被創(chuàng)建*筆者記住這個(gè)時(shí)候set集合至少有兩個(gè)記錄了A和B;
*如果為空就b=new B0;創(chuàng)建一 個(gè)b對(duì)象;
*再次說(shuō)明一一下關(guān)于實(shí)例化一 個(gè)對(duì)象,spring做的很復(fù)雜榜贴, 下次討論
*創(chuàng)建完B的對(duì)象之后,接著完善B的生命周期
*同樣也會(huì)判斷是否允許循環(huán)依賴,如果允許則把對(duì)象b存到第二 個(gè)map當(dāng)中;*提醒- -下筆者這個(gè)時(shí)候第二個(gè)map當(dāng)中至少有兩個(gè)對(duì)象了豌研, a和b
*接著繼續(xù)生命周期;當(dāng)進(jìn)行到b對(duì)象的屬性填充的時(shí)候發(fā)覺b需要依賴A*于是就去容器看看A有沒有創(chuàng)建,說(shuō)白了就是從第一個(gè)map當(dāng)中去找a
*有人會(huì)說(shuō)不上A在前面創(chuàng)建了a嘛?注意那只是個(gè)對(duì)象,不是bean;
*還不在第一 個(gè)map當(dāng)中對(duì)所以b判定A沒有創(chuàng)建妹田,于是就是去創(chuàng)建A;*那么又再次回到了原點(diǎn),創(chuàng)建A的過程中;首先調(diào)用getBean("a")
*上文說(shuō)到getBean("a")的核心就是getSingleton(beanName)
* . 上文也說(shuō)了get出來(lái)a= =null;但是這次卻不等于空了
*這次能拿出一個(gè)a對(duì)象;注意是對(duì)象不是bean
*為什么兩次不同?原因在于getSingleton(beanName)的源碼
* getSingleton(beanName)首先從第一個(gè)map當(dāng)中獲取bean
*這里就是獲取a;但是獲取不到;然后判斷a是不是等于空
*如果等于空則在判斷a是不是正在創(chuàng)建?什么叫做正在創(chuàng)建?
*就是判斷a那個(gè)set集合當(dāng)中有沒有記錄A;
*如果這個(gè)集合當(dāng)中包含了A則直接把a(bǔ)對(duì)象從map當(dāng)中g(shù)et出來(lái)并且返回*所以這一次就不等于空了鹃共,于是B就可以自動(dòng)注入這個(gè)a對(duì)象了
*這個(gè)時(shí)候a還只是對(duì)象鬼佣,a這個(gè)對(duì)象里面依賴的B還沒有注入
*當(dāng)b對(duì)象注入完成a之后,把B的周期走完,存到容器當(dāng)中
*院之后繼續(xù)返回,返回到a注入b哪里?
*因?yàn)閎的創(chuàng)建時(shí)因?yàn)閍需要注入b;于是去get b
*當(dāng)b創(chuàng)建完成一個(gè)bean之后霜浴,返回b(b已經(jīng)是一個(gè)bean了)
*要說(shuō)明的b是一個(gè)bean意味著bE 經(jīng)注入完成了a;這點(diǎn)上面已經(jīng)說(shuō)明了*于返迥了一個(gè)b,故而a也能注入b了;
*接著a對(duì)象繼續(xù)完成生命周期晶衷,當(dāng)完之后a他在容器中了 到齜循環(huán)依賴搞定
*需要說(shuō)明一下上墳提到的正在創(chuàng)建這種說(shuō)法并沒有防支持
*要說(shuō)明一下文提到的正在創(chuàng)建這種說(shuō)法并沒有方支持
*自己的認(rèn)為;各位讀者可以自行給他取名字
*筆者是因?yàn)榇娣拍切┯涗浀膕et集合的名字叫做singletonsCurrentlyInCreation*顧名思義,當(dāng)前正在創(chuàng)建的單例對(duì)象阴孟。晌纫。。永丝。锹漱。
*還有上文提到的對(duì)象和bean的概念;也沒有官方支持
*也是筆為了讓讀者更好的理解spring源碼而提出的個(gè)人概念
*但是如果你覺得這種方法確實(shí)能讓你更好的理解spring源碼
*那么請(qǐng)姑且相信筆者對(duì)spring源碼的理解,假設(shè)10個(gè)人相信就會(huì)有100個(gè)人相信*繼而會(huì)有更多人相信慕嚷,就會(huì)成為官方說(shuō)法哥牍,哈哈。
*以上是循環(huán)依賴的整個(gè)過程喝检,其中g(shù)etSingleton(beanName)
*這個(gè)方法的存在至關(guān)重要
*后說(shuō)明- - -下getSingleton(beanName)的源碼分析嗅辣,下文分析
*/
Object sharedInstance = getSingleton(beanName);
/**
*如果sharedInstance不等于空直接返回
*當(dāng)然這里沒有直接返回而是調(diào)用了getObjectForBeanInstance
*關(guān)于這方法以后解釋,讀者可以認(rèn)為這里可以理解為
* bean =sharedInstance;然后方法最下面會(huì)返回bean
*什么時(shí)候不等于空?
*再容器初始化完成之后.
*程序員直接調(diào)用getbean的時(shí)候不等于空
*什么時(shí)候等于空?
*上已經(jīng)解釋過了,創(chuàng)建對(duì)象的時(shí)候調(diào)用就會(huì)等于空
*/
if(sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
/**
*判斷這個(gè)類是不是在創(chuàng)建過程中
*. 上文說(shuō)了蛇耀,一個(gè)類是否在創(chuàng)建的過程中是第二次調(diào)用getSingleton中決定的*這里還沒有執(zhí)行到辩诞,如果就在創(chuàng)建過程中則出異常
**/
//prototypesCurrentlyInCreation要聯(lián)系getSingleton方法
if(isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
else {
/**
*要說(shuō)明的筆者刪了很多和本文無(wú)用的代碼
*意思就是源碼中執(zhí)行到這個(gè)if的時(shí)候有很多其他代碼
*但是都是一 些判斷,很本文要討論的問題關(guān)聯(lián)不大
*這個(gè)if就是判斷當(dāng)前需要實(shí)例化的類是不是單例的
* spring默認(rèn)都是單例的纺涤,故而一般都成立的
*接下來(lái)便是調(diào)用第二_次 getSingleton
*第二次會(huì)把當(dāng)前正在創(chuàng)建的類記錄到set集合
*然后反射創(chuàng)建這個(gè)實(shí)例译暂,組起生命綢期
*第二次調(diào)用getSingleton的源碼分析會(huì)在下文
* **/
if(mbd.isSingleton0) {
sharedInstance = getSingleton(beanName, () - > {
try {
//完成了目標(biāo)對(duì)象的創(chuàng)建
//如果要代理,還完成了代理
return createBean(beanName, mbd, args);
}
catch(BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put threre
// eagerly by the creation process, to allow for circular referencere solution
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ех;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
return(T) bean;
}
}
}
//第一次調(diào)用getSingleton99#Object sharedInstance = getSingleton(beanName);
//空殼方法
public Object getSingleton(String beanName) { //重點(diǎn)撩炊,-定要記住這里傳的是一個(gè)true, 面試會(huì)考
return getSingleton(beanName, true);
}
/**
. 上面說(shuō)的true對(duì)應(yīng)這里的第二 個(gè)參數(shù)boolean allowEarlyReference
顧名思義叫做允許循環(huán)引用外永,而spring在內(nèi)部調(diào)用這個(gè)方法的時(shí)候傳的true
這也能說(shuō)明spring默認(rèn)是支持循環(huán)引用的,這也是需要講過面試官的
但是你不能只講這一點(diǎn),后面我會(huì)總結(jié),這里先記著這個(gè)true
這個(gè)allowEarlyReference也是支持spring默認(rèn)支持循環(huán)引用的其中一個(gè)原因
**/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
/**首先spring會(huì)去第一個(gè)map當(dāng)中去獲取一 個(gè)bean;說(shuō)白了就是從容器中獲取
說(shuō)明我們?nèi)绻谌萜鞒跏蓟笳{(diào)用getBean其實(shí)就從map中去獲取一個(gè)bean
假設(shè)是初始化A的時(shí)候那么這個(gè)時(shí)候肯定等于空拧咳,前前分析過這個(gè)map的意義
**/
Object singletonObject = this.singletonObjects.get(beanName);
/**
我們這里的場(chǎng)景是初始化對(duì)象A第一次調(diào)用這個(gè)方法
這段代碼非常重要伯顶,首先從容器中拿,如果拿不到,再判斷這個(gè)對(duì)象是不是在set集合
這里的set集合前前E經(jīng)解釋過了骆膝,就是判斷a是不是正在創(chuàng)建
假設(shè)現(xiàn)在a不在創(chuàng)建過程祭衩,那么直接返回一個(gè)空, 第一次getSingleton返回
**/
if(singletonObject == null && isSingletonCurrentlylnCreation(beanName)) lsynchronized(this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if(singletonObject == null && allowEarlyReference) {
ObjectFactory <? > singletonFactory = this.singletonFactories.get(beanName);
if(singletonFactory != null) {
singletonObject = singletonFactory.getObject);
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
return singletonObject;
}
//第二次調(diào)用getSingleton sharedInstance = getSingleton(beanName, 0) ->代碼我做了刪減,刪了一些本本文無(wú)關(guān)的代碼
public Object getSingleton(String beanName, ObjectFactory <? > singletonFactory) {
synchronized(this singletonObjects) {
//首先也是從第一個(gè)map即容器中獲取
//再次證明如果我們?cè)谌萜鞒跏蓟笳{(diào)用getBean其實(shí)就是從map當(dāng)中獲取一個(gè)bean//我們這里的場(chǎng)景是初始化對(duì)象A第一次調(diào)用這個(gè)方法
//那么肯定為空
Object singletonObject = this.singletonObjects.get(beanName);
if(singletonObject == null) {
/**注意這行代碼阅签,就是A的名字添加到set集合當(dāng)中
也就是筆者說(shuō)的標(biāo)識(shí)A正在創(chuàng)建過程當(dāng)中
這個(gè)方法比較簡(jiǎn)單我就不單獨(dú)分析了掐暮,直接在這里給出
這個(gè)方法比較簡(jiǎn)單我就不單獨(dú)分析了,直接在這里給出
singletonsCurrentlyInCreation.add就是放到set集合當(dāng)中
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName)&&
!this. singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
**/
beforeSingletonCreation(beanName);
boolean newSingleton = false;
try {
//這里便是創(chuàng)建一個(gè)bean的入口乃
//spring會(huì)首先實(shí)例化一個(gè)對(duì)象, 然后生命周期
//走生命周期的時(shí)候前面說(shuō)過會(huì)判斷是否允許循環(huán)依賴
//如果允許則會(huì)把創(chuàng)建出來(lái)的這個(gè)對(duì)象放到第二個(gè)map當(dāng)中//然后接著生命周期當(dāng)他走到屬性填充的時(shí)候
//會(huì)去get- -下B政钟,因?yàn)橐畛銪,也就是大家認(rèn)為的自動(dòng)注入//這些代碼下文分析路克,如果完了生命周期
singletonObject = singletonFactory.getObject);
newSingleton = true;
}
}
return singletonObject;
}
}
// 如果允許則會(huì)把創(chuàng)建出來(lái)的這個(gè)對(duì)象放到第個(gè)map當(dāng)中
//
// AbstractAutowireCapableBeanFactory#doCreateBean() Z?S31t45
//
// 由于這個(gè)方法內(nèi)容過去多樟结,我刪減了 - 些無(wú)用代碼 上面說(shuō)的singletonObject =
//
// singletonFactory.getObject();
//
// Ft @JbeaniAbstractAutowireCapableBeanFactory#doCreateBean(EêJ?bean;
//
// 下面分析這個(gè)方法.
protected Object doCreateBean(final String beanName, final RootBeanDefinitionmbd, final@ Nullable Object[] args) throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if(mbd.isSingleton()) {
//如果你bean指定需要通過factoryMethod來(lái)創(chuàng)建則會(huì)在這里被創(chuàng)建//如果讀者不知道上面factoryMethod那你就忽略這行代碼
//你可以認(rèn)為你的A是一個(gè)普通類, 不會(huì)再這里創(chuàng)建
instanceWrapper = this.factoryBeanlnstanceCache.remove(beanName);
if(instanceWrapper == null)(
//這里就通過反射創(chuàng)建一個(gè)對(duì)象, 注意是對(duì)象不是bean
//iX↑c(diǎn)reateBeanlnstanceJiiFER, 4XTtGtT//以后如果有更新再來(lái)分析這個(gè)代碼
//讀者可以理解這里就是new了一個(gè)A對(duì)象
instanceWrapper = createBeanlnstance(beanName, mbd, args);
//得到new出來(lái)的A,為什么需要得到呢?因?yàn)锳new出來(lái)之后存到一個(gè)對(duì)象的屬性當(dāng)中
final Object bean = instanceWrapper.getWrappedlnstance);
//厘點(diǎn):面試會(huì)考.
//這里就是判斷是不是支持循環(huán)引|用和是否單例以及bean是否在創(chuàng)建過程中
//判斷循環(huán)弓|用的是&& this. allowCircularReferences
//allowCircularReferences在spring源碼當(dāng)中默認(rèn)就是true
// private boolean allowCircularReferences = true; 這是spring源碼中的定義//并且這個(gè)屬性上面spring寫了-行徘常重要的注釋
// Whether to automatically try to resolve circular references between beans//讀者自行翻譯,這是支持spring默認(rèn)循環(huán)引用最核心的證據(jù).
//讀者-要講給面試官,關(guān)于怎么講,我后面會(huì)總結(jié)
boolean earlySingletonExposure = (mbd.isSingleton0 && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
//如果是單例,粗正在創(chuàng)建,瓶沒有關(guān)閉循環(huán)引|用則執(zhí)行
//所以spring原形是不支持循環(huán)弓|用的這是證據(jù)精算,但是其實(shí)可以解決
//怎么解決原形的循環(huán)依賴瓢宦,筆者下次更新吧
if(earlySingletonExposure) {
//這里就是這個(gè)創(chuàng)建出來(lái)的A對(duì)象a放到第二個(gè)map當(dāng)中//注意這里addSingletonFactory就是往map當(dāng)中put//需要說(shuō)明的是他的value并不是-個(gè)a對(duì)象
/而是一段表達(dá)式,但是包含了這個(gè)對(duì)象的
//所以上文說(shuō)的第二個(gè)map和第 三個(gè)map的有點(diǎn)不同
//第三個(gè)map是直接放的a對(duì)象(下文會(huì)講到第三個(gè)map的),//第二個(gè)放的是一個(gè)表達(dá)式包含 了a對(duì)象
//為什么要放一個(gè)表達(dá)式?下文分析吧
addSingletonFactory(beanName, () - > getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.Object exposedObject = bean;try {
//填充屬性灰羽,也就是所謂的自動(dòng)注入//這個(gè)代碼我同一張圖來(lái)說(shuō)明
//這個(gè)代碼我同一張圖來(lái)說(shuō)明
poupetean(beaNname mbd, insteWrap exposedObject = ininlean(benlame eposedobject, mbd);
}
return exposedObject;
}
/**創(chuàng)建B的流程和創(chuàng)建A差不多驮履,把B放到set集合,標(biāo)識(shí)B正在創(chuàng)建,繼而實(shí)例化b對(duì)象,然后執(zhí)行生命周期流程,把創(chuàng)建的這個(gè)b對(duì)象放到第二個(gè)map當(dāng)中, 這個(gè)時(shí)候map當(dāng)中已經(jīng)有了a,b兩個(gè)對(duì)象谦趣。
* 然后執(zhí)行b對(duì)象的屬性填充或者叫自動(dòng)注入時(shí)候發(fā)覺需要依賴a,于重復(fù)上面的getbean步驟疲吸,
*調(diào)用getSingleton方法;只不過現(xiàn)在a對(duì)象已經(jīng)可以獲取了故而把獲取出來(lái)的a對(duì)象、臨時(shí)對(duì)象注入給b對(duì)象前鹅,然后走完b的生命周期流程后返回b所表示bean,跟著把這個(gè)b所表示的bean注入給a對(duì)象,
* 最后走完a對(duì)象的其他生命周期流程;循環(huán)依賴流程全部走完;但是好像沒有說(shuō)到第3三個(gè)map,第三個(gè)map到底充當(dāng)了什么角色呢?
* 這個(gè)知識(shí)點(diǎn)非常的重要峭梳,關(guān)于這個(gè)知識(shí)不少書籍和博客都說(shuō)錯(cuò)了舰绘,這也是寫這篇文章的意義;筆者說(shuō)每次讀spring源碼都不-樣的收獲, 這次最大的收獲便是這里了;我們先來(lái)看-下代碼;
* 場(chǎng)景是這樣的葱椭,spring創(chuàng)建A,記住第一次創(chuàng)建A, 過程中發(fā)覺需要依賴B捂寿,于是創(chuàng)建B,創(chuàng)建B的時(shí)候發(fā)覺需要依賴A,于是再一-次創(chuàng)建- 第二次創(chuàng)建A,
* 下面代碼就是基于第二次創(chuàng)建的A來(lái)分析;第二次創(chuàng)建A的時(shí)候依然會(huì)調(diào)用getSingleton,先獲取一下a
**/
protected Object getSingleton(String beanName, boolean allowEarlyReference) { //先從第一個(gè)map獲取a這個(gè)bean, 也就是單例池獲取
Object singletonObject = this singletonObjects.get(beanName);
if(singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
if(singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized(this.singletonObjects) {
//然后從第三個(gè)map當(dāng)中獲取a這個(gè)對(duì)象
singletonObject = this.earlySingletonObjects get(beanName);
//如果第三個(gè)map獲取不到a對(duì)象,再看是否允許了循環(huán)引用
// 而這里的allowEarlyReference是true
//
// 1 為什么是true,.文說(shuō)了這個(gè)方法是spring自 己調(diào)用的孵运,他默認(rèn)傳了true
if(singletonObject == null && allowEarlyReference) {
//然后從第二個(gè)map中獲取一個(gè)達(dá)式
//這要非常注意第二個(gè)map當(dāng)中存的不是一 個(gè) 單純的對(duì)象
//前面說(shuō)了第二個(gè)map當(dāng)中存的是一個(gè)表達(dá)式秦陋, 你可以理解為存了一個(gè)廠//或者理解存了一個(gè)方法,方法里面有個(gè)參數(shù)就是這個(gè)對(duì)象
//安裝spring的命名來(lái)分析應(yīng)該理解為一個(gè)廠singletonFactory
//一個(gè)能夠生成a對(duì)象的工廠
//那么他為什么需要這么一個(gè)廠
//這里我先大概說(shuō)一下治笨,為了過工廠來(lái)改變這個(gè)對(duì)象
//至于為什么要改變對(duì)象,下文我會(huì)分析
//當(dāng)然大部分情況下是不要改變這個(gè)對(duì)象的
//讀者先可以考慮不需要改變這個(gè)對(duì)象,
//那么這個(gè)map里面存的工廠就生產(chǎn)就是這個(gè)原對(duì)象,那么和第三個(gè)map功能-樣
ObjectFactory <? > singletonFactory = this.singletonFactories get(beanName);
if(singletonFactory != nul) {
//調(diào)用表達(dá)式驳概,說(shuō)白了就是調(diào)用工廠的方法,然后改變對(duì)象
//我們假設(shè)對(duì)象不需要改變的情況那么返回了原對(duì)象就是a
//需要改變的情況我們文再分享
singletonObject = singletonFactory.getObject0;
//然后把這個(gè)對(duì)象放到第三個(gè)map當(dāng)中
this.earlySingletonObjects.put(beanName, singletonObject);
//把這個(gè)對(duì)象旷赖、或者表達(dá)式顺又、或者廠從第二個(gè)map中移除
this.singletonFactories.remove(beanName);
//厘點(diǎn):面試會(huì)考--為什么要放到第三三個(gè)?為什么要移除第二個(gè)?
//首先我們通過分析做一個(gè)總結(jié):
// spring首先從第一個(gè)map中拿 a這個(gè)bean
// 不到,從第三個(gè)map當(dāng)中拿a這個(gè)對(duì)象
//
// 不到,從第二個(gè)map拿a這個(gè)對(duì)象或者工廠
//
// 拿到之后放到第三個(gè)map,移除第_一個(gè)map里面的表達(dá)式等孵、或者廠
//
// 如果對(duì)象需要改變稚照,當(dāng)改變完成之后就把他放到第三個(gè)里面
//
// 這里的情況是b需要a而進(jìn)行的步驟,試想- -下以后如果還有C需要依賴a
//
// 就不需要重復(fù)第二個(gè)map的工作 了,也就是改變對(duì)象的工作了俯萌。
//
// 因?yàn)楦淖兺瓿芍蟮腶對(duì)象已經(jīng)在第三個(gè)map中了果录。不知道讀者能不能懂筆者的意思如果對(duì)象不需要改變道理是一樣的, 也同樣在第三個(gè)map取就是了;
//
// 于為什么需要移除第二個(gè)map里面的工廠咐熙、 或者表達(dá)式就更好理解 了
//
// 他E經(jīng)對(duì)a做完了改變,改變之后的對(duì)象已經(jīng)在第三個(gè)map了,為為方便gc啊下面對(duì)為什么需要改變對(duì)象做分
}
}
return singletonObject;
}
}
}
}
// 為什么需要改變對(duì)象?那個(gè)表達(dá)式弱恒、或者說(shuō)工廠主要干什么事呢?那個(gè)工廠、或者表達(dá)式主要是調(diào)用了下面這個(gè)方法
//關(guān)于后置處理器筆者其實(shí)要說(shuō)話很多很多
//現(xiàn)在市面上可見的資料或者書籍對(duì)后置處理器的說(shuō)法筆者-般都不同
//我在B站上傳過一個(gè)4個(gè)小時(shí)的視頻, 其中對(duì)spring后處理器做了詳細(xì)的分析//也提出了-自己的理解和主流理解不同的地方糖声,有興趣同學(xué)可以去看看
//其實(shí)簡(jiǎn)單說(shuō)-這個(gè)方法作用主要是為了來(lái)處理aop的;
斤彼、
/當(dāng)然還有其他功能分瘦,但是一般的讀者 最熟悉的就是aop
//這里我說(shuō)明一下,aop的原理或者流程有很多書籍說(shuō)到過
//但是筆者今天親測(cè)了,現(xiàn)在市面可見的資料和書籍對(duì)aop的說(shuō)法都不全
//很多資料提到aop是在spring bean的生命周期里面填充屬性之后的代理期完成的/而這個(gè)代理周期甚至是在執(zhí)行生命周期回調(diào)方法之后的一個(gè)周期
//那么問題來(lái)了?什么叫spring生命周期回調(diào)方法周期呢?
//首先spring bean生命周期和spring生命周期回調(diào)方法周期是兩個(gè)概念
//spring生命周期回調(diào)方法是spring bean生命周期的一部分琉苇、或者說(shuō)一個(gè)周期
//簡(jiǎn)單理解就是spring bean的生命的某個(gè)過程會(huì)去執(zhí)行spring的生命周期的回調(diào)方法
//此如你在某個(gè)bean的方法上面寫一個(gè)加@ PostConstruct的方法(一 般稱bean初始化方法)
//那么這個(gè)方法會(huì)在spring實(shí)例化一個(gè)對(duì)象之 后嘲玫,琉屬性之后執(zhí)行這個(gè)加注解的方法//我這里叫做spring生命周期回調(diào)方法的生命周期,不是我胡說(shuō)并扇,有官方文檔可以參考的
//在執(zhí)行完spring生命周期回調(diào)方法的生命周期之后才會(huì)執(zhí)行代理生命周期
//在代理這個(gè)生命周期當(dāng)中如果有需要會(huì)完成aop的功能
//以上是現(xiàn)在主流的說(shuō)法去团,也是一般書籍或者"某些大師”的說(shuō)法
//但是在循環(huán)引用的時(shí)候就不一樣了,循環(huán)弓l用的情況下這個(gè)周期這里就完成了aop的代理//這個(gè)周期嚴(yán)格意義上是在填充屬性之前(填充屬性也是一個(gè)生命周期階段)
//填充屬性的周期甚至在生命周期回調(diào)方法之前穷蛹,更在代理這個(gè)周期之前了
//簡(jiǎn)單來(lái)說(shuō)主流說(shuō)法代理的生命周期比如在第8個(gè)周期或者第八步吧
//但是筆者這里得出的結(jié)論土陪,如果- -個(gè)bean是循環(huán)引用的則代理的周期可能在第3步就完成了//那么為什么需要在第三步就完成呢?
//試想一下A、 B兩個(gè)類,現(xiàn)在對(duì)A類做aop處理,也就是需要對(duì)A代理
//
// 不考慮循環(huán)引用spring實(shí)例化A,然后生命周期確實(shí)在第8個(gè)周期完成的代理關(guān)于這個(gè)結(jié)論可以去看b站我講的spring aop源碼分析
//
// 但是如果是循環(huán)依賴就會(huì)有問題
//
// 比如spring實(shí)例化A然后發(fā)現(xiàn)需要注入B這個(gè)時(shí)候A還沒有走到8步
//
// 還沒有完成代理肴熏,發(fā)覺需要注入B,便去創(chuàng)建B,創(chuàng)建B的時(shí)候
//
// 發(fā)覺需要注入A,于是創(chuàng)建A,創(chuàng)建的過程中通過getSingleton
//
// 得到了a對(duì)象鬼雀,注意是對(duì)象,-個(gè)沒有完成代理的對(duì)象
//
// 然后把這個(gè)a注入給B?這樣做合適嗎?注入的a根本沒有aop功能;顯然不合適因?yàn)閎中注入的a需要是一個(gè)代理對(duì)象
//
// 而這個(gè)時(shí)候a存在第二個(gè)map中; 不是一個(gè)代理對(duì)象;
//
// 于是我在第二個(gè)map中就不能單純的存一個(gè)對(duì)象蛙吏, 要存一個(gè)廠
//
// 這個(gè)廠在特殊的時(shí)候需要對(duì)a對(duì)象做改變,比如這里說(shuō)的代理(需要aop功能的情況)這也是三個(gè)map存在的必要性,不知道讀者能不能get到點(diǎn)
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if(!mbd.isSynthetic( && haslnstantiationAwareBeanPostProcessors) {
for(BeanPostProcessor bp: getBeanPostProcessors()) {
if(bp instanceof SmartlnstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartlnstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
// 總結(jié)關(guān)于循環(huán)引用源哩,如何回答面試:
//
// 首先spring在單例的情況下是默認(rèn)支持循環(huán)引用的(當(dāng)然原形也有辦法,今天先不討論);
//
// 在不做任何配置的情況下鸦做,兩個(gè)bean相互依賴是能初始化成功的; spring源碼中在創(chuàng)建bean的時(shí)候先創(chuàng)建這個(gè)bean的對(duì)象励烦,創(chuàng)建對(duì)象完成之后通過判斷容器對(duì)象的
//
// allowCircularReferences屬性決定是否允許緩存這個(gè)臨時(shí)對(duì)象,如果能被緩存成功則通過緩存提前暴露這個(gè)臨時(shí)對(duì)象來(lái)完成循環(huán)依賴;
//
// 而這個(gè)屬性默認(rèn)為true,所以說(shuō)spring默認(rèn)支持循環(huán)依賴的,但是這個(gè)屬性spring提供了api讓程序員來(lái)修改泼诱,所以spring也提供了關(guān)閉循環(huán)引l用的功能;
//
// 再就是spring完成這個(gè)臨時(shí)對(duì)象的生命周期的過程中當(dāng)執(zhí)行到注入屬性或者自動(dòng)裝配的周期時(shí)候會(huì)通過getSingleton方法去得到需要注入的b對(duì)象;
//
// 而b對(duì)象這個(gè)時(shí)候肯定不存在故而會(huì)創(chuàng)建b對(duì)象創(chuàng)建b對(duì)象成功后繼續(xù)b對(duì)象的生命周期坛掠,當(dāng)執(zhí)行到b對(duì)象的自動(dòng)注,入周期時(shí)候會(huì)要求注入a對(duì)象;
//
// 調(diào)用getSingleton;從map緩存中得到a的臨時(shí)對(duì)象(因?yàn)檫@個(gè)時(shí)候a在set集合中;這里可以開講)治筒, 且獲取的時(shí)候也會(huì)判斷是允許循環(huán)弓用,但是判斷的這個(gè)值是通過參數(shù)傳進(jìn)來(lái)的屉栓,也就是spring內(nèi)部調(diào)用的,spring源碼當(dāng)中寫死了為true,故而如果需要擴(kuò)展spring矢炼、或者對(duì)spring=次開發(fā)的的時(shí)候程序員可以自定義這個(gè)值來(lái)實(shí)現(xiàn)自己的功能;不管放到緩存還是從緩存中取出這個(gè)臨時(shí)都需要判斷;而這兩次判斷spring源碼當(dāng)中都是默認(rèn)為true; 這里也能再次說(shuō)明spring默認(rèn)是支持循環(huán)引用的;
//
// 然后面試中可以在說(shuō)說(shuō)兩次調(diào)用getSingleton的意義系瓢,正在創(chuàng)建的那個(gè)set集合有什么用;最后在說(shuō)說(shuō)你在看spring循環(huán)引用的時(shí)候得出的aop實(shí)例化過程的新發(fā)現(xiàn);就比較完美了
//
}