Spring原始碼解析之八finishBeanFactoryInitialization方法即初始化單例bean
七千字長文深刻解讀,Spirng中是如何初始化單例bean的,和麵試中最常問的Spring是如何解決迴圈依賴?
今天解讀Spring核心方法refresh()中最最重要的一個方法finishBeanFactoryInitialization()方法,該方法負責初始化所有的單例bean。
finishBeanFactoryInitialization()方法位於refresh()中下標為8的位置。
到目前為止,應該說 BeanFactory 已經建立完成,並且所有的實現了 BeanFactoryPostProcessor 介面的 Bean 都已經初始化並且其中的 postProcessBeanFactory(factory) 方法已經得到回撥執行了。而且 Spring 已經“手動”註冊了一些特殊的 Bean,如 environment
、systemProperties
等。
剩下的就是初始化 singleton beans 了,大都數我們的業務中都是單例bean,就像我們寫的@Controller、@Service的類(沒有設定懶載入的)都是在這個地方初始化,以供我們使用,如果沒有設定懶載入,那麼 Spring 會在接下來初始化所有的 singleton beans。
我們先看一下refresh()的原始碼,大概看下finishBeanFactoryInitialization(beanFactory)所處的位置。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//1、重新整理前的準備
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//2、將會初始化 BeanFactory、載入 Bean、註冊 Bean
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//3、設定 BeanFactory 的類載入器,新增幾個 BeanPostProcessor,手動註冊幾個特殊的 bean
prepareBeanFactory(beanFactory);
try {
//4、模板方法
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//執行BeanFactory後置處理器
invokeBeanFactoryPostProcessors(beanFactory);
// 5、Register bean processors that intercept bean creation.
//註冊bean後置處理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//國際化
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//6、模板方法--springboot實現了這個方法
onRefresh();
// Check for listener beans and register them.
//7、註冊監聽器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//8、完成bean工廠的初始化**方法重要**********************************************
finishBeanFactoryInitialization(beanFactory);
//9、 Last step: publish corresponding event.
finishRefresh();
}
我們深入finishBeanFactoryInitialization(beanFactory)中,裡面的呼叫線路錯綜複雜,還望讀者可以做好心理準備。
/**
* 負責單例bean的初始化
* 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.
//最先初始化名字為 conversionService的類,conversionService類 它用來將前端傳過來的引數和後端的 controller 方法上的引數進行繫結的時候用
//尤其是用於非基礎型別的轉換
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
//初始化在getBean()方法中實現
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.
// 先初始化 LoadTimeWeaverAware 型別的 Bean aop相關注:大概有個印象,以後解析aop會和它串起來。
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.
//freeze的單詞意思是凍結,這個時候已經開始預初始化, bean 定義解析、載入、註冊先停止
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
//開始初始化
beanFactory.preInstantiateSingletons();
}
該方法是判斷bean的一系列是不是屬於某個型別的bean,如果是就呼叫getBean()方法,如果不是,就呼叫beanFactory.preInstantiateSingletons()進行初始化,我們先把getBean()放一放,重點看一看beanFactory.preInstantiateSingletons()方法。
@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.
// this.beanDefinitionNames 儲存了所有的 beanNames
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
//// 下面這個迴圈,觸發所有的非懶載入的 singleton beans 的初始化操作
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 非抽象、非懶載入的 singletons。如果配置了 'abstract = true',那是不需要初始化的
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 處理 FactoryBean (負責初始化工廠的bean)
if (isFactoryBean(beanName)) {
// FactoryBean 的話,在 beanName 前面加上 ‘&’ 符號
//此處呼叫getBean()方法
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
// 判斷當前 FactoryBean 是否是 SmartFactoryBean 的實現
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) 這個方法就可以進行初始化了
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
// 到這裡說明所有的非懶載入的 singleton beans 已經完成了初始化
// 如果我們定義的 bean 是實現了 SmartInitializingSingleton 介面的,那麼在這裡得到回撥
//如果你想在單例bean初始化後做一些事 那就實現該介面
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();
}
}
}
}
preInstantiateSingletons()方法的主要任務是進行初始化的,在初始化前同樣是一系列判斷,如,是否是懶載入的,是否是一個factorybean(一個特別的bean,負責工廠建立的bean),最後呼叫getBean()方法。
其中有個插曲是否實現了SmartInitializingSingleton介面,將介面讓你可以在bean初始化後做一些事,我們寫一個簡單的例項測試一下。
其他地方讀者看註釋瞭解一下即可,我們開始繼續深入getBean()方法。
getBean()方法內部呼叫了doGetBean()我們直接看doGetBean方法。
// 我們在剖析初始化 Bean 的過程,但是 getBean 方法我們經常是用來從容器中獲取 Bean 用的,注意切換思路,
// 已經初始化過了就從容器中直接返回,否則就先初始化再返回
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// 獲取一個 “正統的” beanName,處理兩種情況,一個是前面說的 FactoryBean(前面帶 ‘&’),
// 一個是別名問題,因為這個方法是 getBean,獲取 Bean 用的,你要是傳一個別名進來,是完全可以的
String beanName = transformedBeanName(name);
// 返回值
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 檢查下是不是已經建立過了
Object sharedInstance = getSingleton(beanName);
// 這裡說下 args ,雖然看上去一點不重要。前面我們一路進來的時候都是 getBean(beanName),
// 所以 args 傳參其實是 null 的,但是如果 args 不為空的時候,那麼意味著呼叫方不是希望獲取 Bean,而是建立 Bean
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 的話,直接返回 sharedInstance,
// 如果是 FactoryBean 的話,返回它建立的那個例項物件
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 建立過了此 beanName 的 prototype 型別的 bean,那麼拋異常,
// 往往是因為陷入了迴圈引用 哦,原來之前的迴圈依賴都是在這拋的異常,再有問題就不是無頭蒼蠅了
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
// 檢查一下這個 BeanDefinition 在容器中是否存在 BeanDefinition既是包含了bean的一系列資訊
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// 如果當前容器不存在這個 BeanDefinition,試試父容器中有沒有
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) {
// typeCheckOnly 為 false,將當前 beanName 放入一個 alreadyCreated 的 Set 集合中。
markBeanAsCreated(beanName);
}
/*
* 稍稍總結一下:
* 到這裡的話,要準備建立 Bean 了,對於 singleton 的 Bean 來說,容器中還沒建立過此 Bean;
* 對於 prototype 的 Bean 來說,本來就是要建立一個新的 Bean。
*/
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// 先初始化依賴的所有 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.
// 如果是 singleton scope 的,建立 singleton 的例項
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
// 執行建立 Bean,詳情繼續深入
// 第三個引數 args 陣列代表建立例項需要的引數,不就是給構造方法用的引數,或者是工廠 Bean 的引數嘛,不過要注意,在我們的初始化階段,args 是 null。
// 這回我們要到一個新的類了 AbstractAutowireCapableBeanFactory,看類名,AutowireCapable?類名是不是也說明了點問題了。
// 主要是為了以下場景,採用 @Autowired 註解注入屬性值:
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);
}
// 如果是 prototype scope 的,建立 prototype 的例項
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
// 執行建立 Bean
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;
}
具體的例項化過程在createBean()方法中,我們繼續深入createBean()方法。
@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.
// 確保 BeanDefinition 中的 Class 被載入
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
// 準備方法覆寫,這裡又涉及到一個概念:MethodOverrides,它來自於 bean 定義中的 <lookup-method />
// 和 <replaced-method />,如果讀者感興趣,回到 bean 解析的地方看看對這兩個標籤的解析。
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.
// 讓 InstantiationAwareBeanPostProcessor 在這一步有機會返回代理,
// 在 《Spring AOP 原始碼分析》那篇文章中有解釋,這裡先跳過
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);
}
}
我們繼續往裡看 doCreateBean 這個方法,這個呼叫過程是真的深。
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) {
// 說明不是 FactoryBean,這裡例項化 Bean,這裡非常關鍵,細節之後再說**********
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);
// 還記得 init-method 嗎?還有 InitializingBean 介面?還有 BeanPostProcessor 介面?
// 這裡就是處理 bean 初始化完成後的各種回撥**************
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 方法,總的來說,我們已經說完了整個初始化流程。
在例項化bean後有一個特別重要的知識點,也是面試中最常問的,Spring怎麼解決迴圈依賴問題?核心程式碼就在這個方法裡面。
迴圈依賴其實就是迴圈引用,也就是兩個或則兩個以上的bean互相持有對方,最終形成閉環。比如A依賴於B,B依賴於C,C又依賴於A。如下圖:
doCreateBean 方法有三個核心流程。
(1)createBeanInstance:例項化,其實也就是呼叫物件的構造方法例項化物件
(2)populateBean:填充屬性,這一步主要是多bean的依賴屬性進行填充
(3)initializeBean:呼叫spring xml中的init 方法。
從上面講述的單例bean初始化步驟我們可以知道,迴圈依賴主要發生在第一、第二步。也就是構造器迴圈依賴和field迴圈依賴。
那麼我們要解決迴圈引用也應該從初始化過程著手,對於單例來說,在Spring容器整個生命週期內,有且只有一個物件,所以很容易想到這個物件應該存在Cache中,Spring為了解決單例的迴圈依賴問題,使用了三級快取。
我們看一下getSingleton方法。
該方法還依賴於三個map,這三個map就是三級快取。
/** Cache of singleton objects: bean name to bean instance. */
//單例物件的cache
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
// 單例物件工廠的cache
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
//提前曝光的單例物件的Cache
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
//判斷當前單例bean是否正在建立中,也就是沒有初始化完成(比如A的構造器依賴了B物件所以得先去建立B物件
// 或則在A的populateBean過程中依賴了B物件,得先去建立B物件,這時的A就是處於建立中的狀態。
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
// 是否允許從singletonFactories中通過getObject拿到物件
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;
}
分析getSingleton()的整個過程,Spring首先從一級快取singletonObjects中獲取。如果獲取不到,並且物件正在建立中,就再從二級快取earlySingletonObjects中獲取。
如果還是獲取不到且允許singletonFactories通過getObject()獲取,就從三級快取singletonFactory.getObject()(三級快取)獲取,如果獲取到了則:
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
從singletonFactories中移除,並放入earlySingletonObjects中。其實也就是從三級快取移動到了二級快取。
從上面三級快取的分析,我們可以知道,Spring解決迴圈依賴的訣竅就在於singletonFactories這個三級cache。
裡就是解決迴圈依賴的關鍵,這段程式碼發生在createBeanInstance之後,也就是說單例物件此時已經被建立出來(呼叫了構造器)。這個物件已經被生產出來了,雖然還不完美(還沒有進行初始化的第二步和第三步),但是已經能被人認出來了(根據物件引用能定位到堆中的物件),所以Spring此時將這個物件提前曝光出來讓大家認識,讓大家使用。
這樣做有什麼好處呢?
讓我們來分析一下“A的某個field或者setter依賴了B的例項物件,同時B的某個field或者setter依賴了A的例項物件”這種迴圈依賴的情況。
A首先完成了初始化的第一步,並且將自己提前曝光到singletonFactories中,此時進行初始化的第二步,發現自己依賴物件B,此時就嘗試去get(B),發現B還沒有被create,所以走create流程,B在初始化第一步的時候發現自己依賴了物件A,於是嘗試get(A),嘗試一級快取singletonObjects(肯定沒有,因為A還沒初始化完全),嘗試二級快取earlySingletonObjects(也沒有),嘗試三級快取singletonFactories,由於A通過ObjectFactory將自己提前曝光了,所以B能夠通過ObjectFactory.getObject拿到A物件(雖然A還沒有初始化完全,但是總比沒有好呀),B拿到A物件後順利完成了初始化階段1、2、3,完全初始化之後將自己放入到一級快取singletonObjects中。
此時返回A中,A此時能拿到B的物件順利完成自己的初始化階段2、3,最終A也完成了初始化,進去了一級快取singletonObjects中,而且更加幸運的是,由於B拿到了A的物件引用,所以B現在hold住的A物件完成了初始化。
知道了這個原理時候,肯定就知道為啥Spring不能解決“A的構造方法中依賴了B的例項物件,同時B的構造方法中依賴了A的例項物件”這類問題了!因為加入singletonFactories三級快取的前提是執行了構造器,所以構造器的迴圈依賴沒法解決。
接下來我們挑 doCreateBean 中的三個細節出來說說。一個是建立 Bean 例項的 createBeanInstance 方法,一個是依賴注入的 populateBean 方法,還有就是回撥方法 initializeBean。
這三個方法也是極其複雜的,讀者有興趣可以繼續的深入進去。
1、 createBeanInstance 方法
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// 確保已經載入了此 class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 校驗一下這個類的訪問許可權
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
if (mbd.getFactoryMethodName() != null) {
// 採用工廠方法例項化,不熟悉這個概念的讀者請看附錄,注意,不是 FactoryBean
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
// 如果不是第一次建立,比如第二次建立 prototype bean。
// 這種情況下,我們可以從第一次建立知道,採用無參建構函式,還是建構函式依賴注入 來完成例項化
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
// 建構函式依賴注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 無參建構函式
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
// 判斷是否採用有參建構函式
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 建構函式依賴注入
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
// 建構函式依賴注入
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
// 呼叫無參建構函式
return instantiateBean(beanName, mbd);
}
看一下instantiateBean方法是怎麼做的。
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
try {
Object beanInstance;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(
(PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),
getAccessControlContext());
}
else {
// 例項化
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
}
// 包裝一下,返回
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
我們可以看到,關鍵的地方在於:beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
裡面是具體是例項化過程,我們進去看看。
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
// 如果不存在方法覆寫,那就使用 java 反射進行例項化,否則使用 CGLIB,
// 方法覆寫 請參見附錄"方法注入"中對 lookup-method 和 replaced-method 的介紹
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(
(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// 利用構造方法進行例項化
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
// 存在方法覆寫,利用 CGLIB 來完成例項化,需要依賴於 CGLIB 生成子類,這裡就不展開了。
// tips: 因為如果不使用 CGLIB 的話,存在 override 的情況 JDK 並沒有提供相應的例項化支援
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
到這裡,我們就算例項化完成了。我們開始說怎麼進行屬性注入。
2、populateBean 方法
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;
}
}
}
}
// bean 例項的所有屬性都在這裡了
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 通過名字找到所有屬性值,如果是 bean 依賴,先初始化依賴的 bean。記錄依賴關係
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);
}
// 這裡有個非常有用的 BeanPostProcessor 進到這裡: AutowiredAnnotationBeanPostProcessor
// 對採用 @Autowired、@Value 註解的依賴進行設值,這裡的內容也是非常豐富的
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) {
// 設定 bean 例項的屬性值
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
屬性注入完成後,這一步其實就是處理各種回撥了,這塊程式碼比較簡單。
3、 initializeBean方法
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 如果 bean 實現了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 介面,回撥
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessor 的 postProcessBeforeInitialization 回撥
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 處理 bean 中定義的 init-method,
// 或者如果 bean 實現了 InitializingBean 介面,呼叫 afterPropertiesSet() 方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessor 的 postProcessAfterInitialization 回撥
//BeanPostProcessor 的兩個回撥都發生在這邊,只不過中間處理了 init-method
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
自此,Spring例項化單例非懶載入bean的過程也就完成了,這也是Spirng最最重要的方法了。在我們的日常使用Spring中,定義好各個類,然後在上面加上,@Controller,@Service,Autowired等註解,這些註解是怎麼起作用的呢?
想必大部分同學都是知其然,不知其所以然,想必通過本文,讀者心中能有一個清楚的認識。