前言
承上啟下:
- Spring的
refresh
->finishBeanFactoryInitialization
(容器初始化單例非延遲加載Bean的入口). -
beanFactory.preInstantiateSingletons();
代态,Bean工廠開始加載Bean實例. - 獲取beanName列表吐限,循環(huán)對每個beanName進行
getBean
操作. -
getBean
中調(diào)用了doGetBean
進行了一些創(chuàng)建Bean的前置處理.最終在getSingleton
中調(diào)用了createBean
進行Bean的創(chuàng)建.
OK,下面進入今天的主題-createBean.
createBean的總體流程
- 解析Bean類型,獲取Class: resolveBeanClass.
- 檢查和準備Bean中的方法覆蓋: prepareMethodOverrides.
- 應(yīng)用實例化之前的后處理器: resolveBeforeInstantiation.
- 開始創(chuàng)建Bean: doCreateBean
1. resolveBeanClass-解析Bean類型,獲取Bean的Class.
- AbstractAutowireCapableBeanFactory#createBean
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;
// 確認當(dāng)前的Bean類是可以被解析的输瓜,并且支持克隆BeanDefinition,merged的BeanDefinition不在此方法的考慮范圍
// 進入到里面敬察,會發(fā)現(xiàn)器通過了類加載器進行了Class的獲取
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
// 克隆一份BeanDefinition,用來設(shè)置上加載出來的對象
// 采用副本的原因是某些類可能需要動態(tài)加載Class
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// 省略若干代碼
}
容器在前面已經(jīng)加載并注冊好了
BeanDefinition
,它描述了關(guān)于Bean的信息回俐,在此處Spring要開始將自己抽象出來的BeanDefinition
進行解析.這里思考一個問題,為什么Spring在加載Bean的時候選擇了RootBeanDefinition
進行解析,而不是之前在加載BeanDefinition
的時候反復(fù)說到的GenericBeanDefinition
?
RootBeanDefinition
對應(yīng)的是Java中的繼承體系而制造的復(fù)合BeanDefinition
(Spring在定義Bean時域慷,也支持定義繼承關(guān)系).從各種容器加載出來的BeanDefinition
环形,最終都會通過getMergedLocalBeanDefinition
轉(zhuǎn)化成RootBeanDefinition
.
RootBeanDefinition
可以合成有繼承關(guān)系的BeanDefinition
(如果沒有繼承關(guān)系,那么自己便是代表parent).這里推薦一篇文章,希望可以帶來更多的思考: 【小家Spring】Spring IoC容器中核心定義之------BeanDefinition深入分析(RootBeanDefinition谤草、ChildBeanDefinition...)
OK,回到主題,拿到傳進來的
RootBeanDefinition
后跟束,Spring需要確認當(dāng)前的Bean類是可以被解析的,即是否能通過類加載器進行載入.對于注解容器來說,在組件掃描的時候就通過ResourceLoader進行了資源的定位丑孩,所以在這里是可以確認可以被解析的.
考慮到健全性冀宴,Spring還是謹慎地進行了校驗,畢竟不是所有的BeanDefinition
都是通過注解容器加載的.
- AbstractBeanFactory#resolveBeanClass
protected Class<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch)
throws CannotLoadBeanClassException {
try {
// 如果當(dāng)前BeanDefinition存儲beanClass屬于Class實例,直接返回
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
}
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>)
() -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
}
else {
// 如果當(dāng)前BeanDefinition沒有存儲Class實例,那么嘗試解析
return doResolveBeanClass(mbd, typesToMatch);
}
}
catch (PrivilegedActionException pae) {
ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
}
catch (ClassNotFoundException ex) {
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
}
catch (LinkageError err) {
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
}
}
- AbstractBeanFactory#doResolveBeanClass
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
throws ClassNotFoundException {
ClassLoader beanClassLoader = getBeanClassLoader();
ClassLoader dynamicLoader = beanClassLoader;
boolean freshResolve = false;
if (!ObjectUtils.isEmpty(typesToMatch)) {
// When just doing type checks (i.e. not creating an actual instance yet),
// use the specified temporary class loader (e.g. in a weaving scenario).
ClassLoader tempClassLoader = getTempClassLoader();
if (tempClassLoader != null) {
dynamicLoader = tempClassLoader;
freshResolve = true;
if (tempClassLoader instanceof DecoratingClassLoader) {
DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
for (Class<?> typeToMatch : typesToMatch) {
dcl.excludeClass(typeToMatch.getName());
}
}
}
}
// 獲取BeanDefinition的className.
String className = mbd.getBeanClassName();
if (className != null) {
// 根據(jù)className解析成表達式
Object evaluated = evaluateBeanDefinitionString(className, mbd);
if (!className.equals(evaluated)) {
// A dynamically resolved expression, supported as of 4.2...
if (evaluated instanceof Class) {
return (Class<?>) evaluated;
}
else if (evaluated instanceof String) {
className = (String) evaluated;
freshResolve = true;
}
else {
throw new IllegalStateException("Invalid class name expression result: " + evaluated);
}
}
if (freshResolve) {
// When resolving against a temporary class loader, exit early in order
// to avoid storing the resolved Class in the bean definition.
if (dynamicLoader != null) {
try {
// 如果解析后的表達式為Class則直接返回
return dynamicLoader.loadClass(className);
}
catch (ClassNotFoundException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
}
}
}
// 反射工具類加載Class
return ClassUtils.forName(className, dynamicLoader);
}
}
// Resolve regularly, caching the result in the BeanDefinition...
return mbd.resolveBeanClass(beanClassLoader);
}
這里Spring會獲取到當(dāng)前工廠的類加載器温学,然后從BeanDefinition中獲取className.Spring會先對className做表達式解析略贮,如果不是通過表達式進行解析,那么調(diào)用
ClassUtils.forName(className, dynamicLoader);
,如果className不存在仗岖,再使用類加載器進行加載.類于類加載器是一一對應(yīng)的關(guān)系逃延,Spring需要找到可以加載該類的類加載器,然后加載出Class對象.
2. 檢查和準備Bean中的方法覆蓋-prepareMethodOverrides
- AbstractAutowireCapableBeanFactory#createBean
// Prepare method overrides.
// 檢查和準備Bean中的方法覆蓋
try {
mbdToUse.prepareMethodOverrides();
}
- AbstractBeanDefinition#prepareMethodOverrides
主要針對
lookup methods
做校驗和方法覆蓋。現(xiàn)在用得比較少了.
如果對Lookup方法注入
有興趣轧拄,可以在Spring的官網(wǎng)查看: 點我前往
- AbstractBeanDefinition#prepareMethodOverrides
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exist and determine their overloaded status.
// 檢查查找方法是否存在揽祥,并確定其重載狀態(tài)。
if (hasMethodOverrides()) {
getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
}
}
- AbstractBeanDefinition#prepareMethodOverride
驗證并準備給定的方法是否被重寫紧帕。檢查是否存在具有指定名稱的方法盔然,如果找不到該方法,則將其標記為未重載是嗜。
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
if (count == 0) {
throw new BeanDefinitionValidationException(
"Invalid method override: no method with name '" + mo.getMethodName() +
"' on class [" + getBeanClassName() + "]");
}
// 如果不存在重載,在使用CGLIB增強階段就不需要校驗了
else if (count == 1) {
// Mark override as not overloaded, to avoid the overhead of arg type checking.
// 將替代標記為未過載愈案,以避免arg類型檢查的開銷。
mo.setOverloaded(false);
}
}
3. 激活Bean實例化前的后置處理器-resolveBeforeInstantiation
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 解析BeanPostProcessors的BeanPostProcessorsBeforeInstantiation,試圖返回一個需要創(chuàng)建Bean的代理對象
// resolveBeforeInstantiation只針對有自定義的targetsource.
// 因為自定義的targetsource不是Spring的bean,那么后續(xù)的初始化與該bean無關(guān)
// 因此直接可以進行代理
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);
}
- AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
// 如果beforeInstantiationResolved為false
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
// 如果注冊了InstantiationAwareBeanPostProcessors的BeanPostProcessor.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 執(zhí)行實現(xiàn)了該后置處理器接口的類中postProcessBeforeInitialization方法
// Spring在這里使用了責(zé)任鏈模式,如果有一個后置處理器可以返回Object,就會馬上跳出循環(huán)
// 同時鹅搪,如果第三方框架在此后置處理器對Bean執(zhí)行了操作站绪,那么將不會進入到doCreateBean中了.
// 注意傳參,這里傳入的是一個class和beanName.
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
如果當(dāng)前的Bean實現(xiàn)了InstantiationAwareBeanPostProcessor接口丽柿,并且在postProcessBeforeInstantiation中返回了Object恢准,那么Spring將不會執(zhí)行
doCreateBean
進行實例化,而是將當(dāng)前用戶返回的bean實例直接返回甫题。
AbstractAutoProxyCreator
這個AOP代理的BeanPostProcessor便是這樣做的.
執(zhí)行完before的操作后馁筐,如果返回了實例,那么繼續(xù)執(zhí)行after的操作.
其中,before和after的執(zhí)行邏輯有點區(qū)別:
before方法執(zhí)行的中斷條件:
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
after方法執(zhí)行的中斷條件:
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
關(guān)注這個BeanPostPorcessor坠非,在后續(xù)的學(xué)習(xí)中敏沉,我們?nèi)阅茉谶^濾器中學(xué)習(xí)到這種職責(zé)鏈的設(shè)計原則.
我們來看看InstantiationAwareBeanPostProcessor的接口清單.默認返回null.
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
}
4. 開始創(chuàng)建Bean-doCreateBean
OK,再梳理一下思路,從createBean中,Spring分析了當(dāng)前的Class是否能被類加載器加載,如果可以加載盟迟,返回當(dāng)前
BeanDefinitino
的Class對象,接著進行了Lookup method
的檢查秋泳,最后激活了InstantiationAwareBeanPostProcessors
的方法,如果以上方法都沒中斷,那么Spring將進行Bean的實例化-doCreateBean.
try {
// 創(chuàng)建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);
}
總結(jié)
- 在createBean階段攒菠,Spring會分析當(dāng)前BeanDefinition的Class是否是可解析的.具體表現(xiàn)為用類加載器進行l(wèi)oadClass或者Class.forName
- 檢查當(dāng)前BeanDefinition的Lookup method是否存在迫皱,并且確認重載狀態(tài).
- 如果實現(xiàn)了
InstantiationAwareBeanPostProcessors
,激活此后置處理器,如果可以從此后置處理器中獲取Bean實例辖众,那么直接返回該Bean實例卓起,不會進行doCreateBean
操作. - 開始Bean的實例化-doCreateBean.
doCreateBean篇幅較長,將拆分幾篇文章進行講解赵辕,如果覺得不錯既绩,請關(guān)注我的博客~