上周主要了解了spring boot項目啟動過程中希坚,beanFactory的繼承體系,以及beanFactory是怎么創(chuàng)建的玛痊。今天繼續(xù)來看下beanFactory這個容器的詳細(xì)信息锌俱,因為beanFactory屬性和方法比較多迎膜,今天主要看下它比較重要的幾個屬性和方法负蚊。
一神妹、屬性
beanFactory負(fù)責(zé)管理bean的加載,實例化家妆,維護bean之間的依賴關(guān)系鸵荠,負(fù)責(zé)bean的聲明周期,再加上DefaultListableBeanFactory的父類也比較多伤极,也導(dǎo)致了beanFactory屬性非常的多蛹找。下面是我認(rèn)為比較重要的一些屬性,這些屬性可能是定義在DefaultListableBeanFactory類中塑荒,也可能定義在其父類中熄赡,但是為了方便我就全部寫到一起了姜挺,下面是代碼:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
// 繼承子父類的屬性
// 創(chuàng)建bean實例的策略齿税,使用的是cglib
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
// 是否自動嘗試解析bean之間的循環(huán)引用
private boolean allowCircularReferences;
// 在依賴性檢查和自動裝配時忽略的依賴關(guān)系類型,存儲的為Class對象
private final Set<Class<?>> ignoredDependencyTypes;
// 在依賴性檢查和自動裝配時忽略的依賴關(guān)系類型炊豪,存儲的為Class對象凌箕。默認(rèn)值忽略BeanFactory
private final Set<Class<?>> ignoredDependencyInterfaces;
// 當(dāng)前正在創(chuàng)建的bean的名稱,用于從用戶指定的Supplier回調(diào)觸發(fā)的getBean等調(diào)用的隱式依賴注冊词渤。
private final NamedThreadLocal<String> currentlyCreatedBean;
// 是否緩存bean的元數(shù)據(jù)牵舱,或者每次訪問時重新獲取
private boolean cacheBeanMetadata = true;
// 要在createBean中應(yīng)用的BeanPostProcessors
private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList();
// 從bean名稱映射到合并的RootBeanDefinition
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap(256);
// 已經(jīng)創(chuàng)建至少一次的bean的名稱
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap(256));
// 當(dāng)前正在創(chuàng)建的bean的名稱
private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal("Prototype beans currently in creation");
// 本身的屬性值//
// 是否允許使用相同bean名稱重新注冊不同的bean定義,即注冊的兩個相同的名字的bean缺虐,且用后面的bean覆蓋前面的
private boolean allowBeanDefinitionOverriding = true;
// 是否允許預(yù)加載
private boolean allowEagerClassLoading = true;
// 檢查bean定義是否為一個autowire注入的解析器
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
// 根據(jù)依賴類型映射到相應(yīng)的自動注入的值map集合
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap(16);
// 鍵值是bean名稱芜壁,映射值為bean定義對象的map集合
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
// 以依賴類型的類對象為鍵,所有bean(單例非單例)的名稱為值得map集合
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap(64);
// 以依賴類型的類對象為鍵高氮,所有單例bean的名稱為值的map集合
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap(64);
// bean定義的名稱list慧妄,按照注冊順序
private volatile List<String> beanDefinitionNames = new ArrayList(256);
// 省略
....
}
看到這里我就記得上次中遇到的一個問題,就是同名bean的創(chuàng)建剪芍,當(dāng)時日志顯示的當(dāng)前bean的類型不是期望的類型塞淹,因為allowBeanDefinitionOverriding的屬性值默認(rèn)為true。當(dāng)然這個屬性是可以修改的罪裹,有興趣可以網(wǎng)上找一下相關(guān)方法饱普。有些屬性又會涉及到很多不太熟悉的類,比如AutowireCandidateResolver状共、BeanDefinition套耕、RootBeanDefinition等等,AutowireCandidateResolver是檢查bean是否通過Autowire注入的解析器峡继。BeanDefinition描述了一個bean實例箍铲,它保存相關(guān)的屬性值,構(gòu)造函數(shù)參數(shù)值以及具體實現(xiàn)提供的更多信息鬓椭。RootBeanDefinition表示合并的bean定義颠猴,它在運行時支持BeanFactory中的特定bean关划,它本質(zhì)上是運行時的“統(tǒng)一”bean定義視圖。反正遇到不清楚的就去看下源碼的注解翘瓮,有時不一定非要特別清楚贮折,了解它的作用就行。接下來我們看下相關(guān)的一些方法吧资盅,同樣的调榄,這些方法可能是DefaultListableBeanFactory類,也可能是其父類的呵扛。
二每庆、相關(guān)方法
方法也非常多,一樣選擇幾個來看今穿。beanFactory負(fù)責(zé)bean的加載缤灵、實例化以及相互之間的關(guān)系,我們對應(yīng)一個一個蓝晒。
1腮出、創(chuàng)建bean
創(chuàng)建bean的方法來自于AbstractAutowireCapableBeanFactory,下面我們看看源碼芝薇,簡單的分析一下大概的過程胚嘲。
public <T> T createBean(Class<T> beanClass) throws BeansException {
RootBeanDefinition bd = new RootBeanDefinition(beanClass);
bd.setScope(SCOPE_PROTOTYPE);
bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());
return (T) createBean(beanClass.getName(), bd, null);
}
首先以類對象為參數(shù)創(chuàng)建出RootBeanDefinition實例,然后設(shè)置其為原型模式洛二,即prototype馋劈,這樣的目的就是為了避免它作為一個依賴bean存在,因為每個RootBeanDefinition創(chuàng)建都需要一個對應(yīng)的bean的類對象晾嘶。然后調(diào)用下面的方法
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;
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
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) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
這個方法里面先執(zhí)行resolveBeanClass(mbd, beanName)方法妓雾,即根據(jù)RootBeanDefinition實例和bean名稱為參數(shù),去解析對應(yīng)的類對象变擒,返回結(jié)果為bean名稱的類對象君珠。這個過程中會將已解析的Class存儲在bean定義中以供進(jìn)一步使用。然后執(zhí)行prepareMethodOverrides方法娇斑,該方法主要為了驗證并準(zhǔn)備為此bean定義的方法覆蓋策添,檢查其是否存在具有指定名稱的方法。然后是resolveBeforeInstantiation方法毫缆,即在實例化之前解析唯竹,這個方法為BeanPostProcessors提供返回代理對象而不是目標(biāo)bean實例的機會,也就是說如果在實例化之間檢驗是否有這個bean的一個代理對象苦丁,有的話直接返回該代理對象浸颓,否則繼續(xù)執(zhí)行下面doCreateBean方法,我們看下doCreateBean源碼
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
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;
}
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;
}
}
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
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 " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
1、這個方法先判斷RootBeanDefinition是否為單例产上,如果為單例則從factoryBeanInstanceCache中移除該bean名稱棵磷,否則執(zhí)行2。
2晋涣、執(zhí)行createBeanInstance方法創(chuàng)建bean實例仪媒,這個方法會使用適當(dāng)?shù)膶嵗呗詾橹付ǖ腷ean創(chuàng)建新實例:比如工廠方法,構(gòu)造函數(shù)自動裝配或簡單實例化谢鹊,返回結(jié)果是一個bean的包裝類對象算吩。getWrappedInstance和getWrappedClass方法反別返回相應(yīng)的bean對象和bean的類對象,并將該類對象賦值給resolvedTargetType佃扼。
3偎巢、接下來的同步代碼塊主要是為了允許post-processors(后處理器)修改合并的bean定義,即將MergedBeanDefinitionPostProcessors應(yīng)用于指定的bean定義兼耀,并調(diào)用其postProcessMergedBeanDefinition方法压昼。關(guān)于這點我也還不是太理解具體的作用。
4翠订、判斷是否支持earlySingletonExposure巢音,即熱緩存單例遵倦,以保證即使在BeanFactoryAware等生命周期接口觸發(fā)時也能夠解析循環(huán)引用尽超。如果是則將創(chuàng)建新的單例工廠以構(gòu)建指定的單例bean。
5梧躺、初始化bean實例似谁,先執(zhí)行populateBean方法,即使用bean定義中的屬性值填充給定bean的包裝類對象中的bean實例掠哥。然后執(zhí)行initializeBean方法巩踏,初始化給定的bean實例,應(yīng)用工廠回調(diào)以及init方法和bean后處理器续搀。
6塞琼、判斷earlySingletonExposure屬性值,如果為true禁舷,則獲取早期的單例bean引用彪杉,如果不為空進(jìn)行后續(xù)判斷判斷初始化后的exposedObject和第2步中的bean是否同一個bean,是將將早期單列bean引用賦值給exposedObject牵咙,否則繼續(xù)進(jìn)行其他判斷派近。
7、執(zhí)行registerDisposableBeanIfNecessary方法洁桌,將bean注冊為一次性bean渴丸。最后返回相應(yīng)bean實例。
當(dāng)然我說是比較簡單的,其實中間過程非常的復(fù)雜谱轨,因為涉及的方法很多戒幔,自己沒辦法每一個都貼一段代碼,所以只能將就看吧土童。
2溪食、初始化bean
初始化給定的bean實例,應(yīng)用工廠回調(diào)以及init方法和bean后處理器娜扇。這個在上面的createBean方法中有調(diào)用過错沃,我們看下具體的代碼
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
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()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
1、判斷系統(tǒng)的securityManager是否為null雀瓢,不為null執(zhí)行AccessController.doPrivileged方法枢析;否則執(zhí)行2。
2刃麸、執(zhí)行invokeAwareMethods方法醒叁,該方法兩個參數(shù),分別為bean名稱beanName和實例bean泊业。判斷給定的bean是否為BeanNameAware實例把沼,是則將bean實例名稱設(shè)置為beanName;判斷給定的bean是否為BeanClassLoaderAware實例吁伺,然后獲取ClassLoader饮睬,不為空是則將ClassLoader引用賦值給bean的beanClassLoader變量;最后判斷bean實例是否為BeanFactoryAware篮奄,是則調(diào)用setBeanFactory方法捆愁,將AbstractAutowireCapableBeanFactory實例賦值給bean的beanFactory變量。
3窟却、將bean實例賦值給變量wrappedBean昼丑,然后判斷RootBeanDefinition即mbd是否為null或者mbd為非合成,執(zhí)行applyBeanPostProcessorsBeforeInitialization方法夸赫,該方法會獲取到BeanPostProcessor實例菩帝,并執(zhí)行各自的postProcessBeforeInitialization實現(xiàn),其返回的bean實例可能是是原始實例的包裝器對象茬腿。
4呼奢、執(zhí)行invokeInitMethods方法,這個方法會將bean所有屬性值都被設(shè)置滓彰,并了解它屬于的bean工廠控妻。這個需要檢查該bean是否實現(xiàn)了InitializingBean或定義了一個自定義init方法,并調(diào)用必要的回調(diào)方法揭绑」颍看下面的代碼:
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
先判斷bean是否實現(xiàn)了InitializingBean郎哭,如果是,且滿足其他判斷條件菇存,則執(zhí)行afterPropertiesSet方法夸研。如果mbd不為null,且bean實例的類對象不為NullBean依鸥,則從RootBeanDefinition實例獲取initMethodName名稱亥至,如果滿足判斷條件,則執(zhí)行invokeCustomInitMethod方法贱迟,該方法通過反射執(zhí)行自定義的init方法姐扮。
5、執(zhí)行mbd為null或者mbd.isSynthetic()為false的判斷條件衣吠,滿足條件執(zhí)行applyBeanPostProcessorsAfterInitialization茶敏,即完成初始化后應(yīng)用BeanPostProcessors方法,該方法和3中的applyBeanPostProcessorsBeforeInitialization方法比較相像缚俏,都是執(zhí)行每個PostProcessor各自的postProcessAfterInitialization方法惊搏。最后返回wrappedBean,這個是一個原始bean的包裝器對象忧换。
其實初始化bean的方法應(yīng)該算是創(chuàng)建bean的一個部分恬惯,我為了區(qū)分就單獨拿出來了,今天主要就是了解beanFactory的成員變量以及兩個方法亚茬,但是這兩個方法比我想象的還是要復(fù)雜一點酪耳,代碼還是蠻多的,關(guān)于其他的一些方法我們下次繼續(xù)再看才写。
最后想說一下周五的一個面試情況葡兑,自己雖然投了十幾份簡歷也就那么2奖蔓、3家面試邀請赞草,但是因為在異地,自己拒了一家吆鹤。星期五我覺得很有必要去面一下厨疙,請假去了上海。周五面的是中通快遞疑务,地點很偏僻沾凄,面試體驗也并不太好,當(dāng)然自己也沒有怎么準(zhǔn)備(有點托大知允,后悔)撒蟀。面試問題主要是Java基礎(chǔ),多線程我說沒怎么用過面試官就沒問了温鸽,其實這部分自己看得東西也蠻多的保屯;然后spring cloud和dubbo對比手负,這個我沒回答好,缺少實際的使用經(jīng)驗姑尺。mybatis的一點基礎(chǔ)OGNL表達(dá)式和EL表達(dá)式的區(qū)別竟终,我只記得OGNL能更好的防止SQL注入;redis持久化的兩種方式切蟋,自認(rèn)為答的還行统捶,畢竟前段時間剛學(xué)了;然后就是Java基礎(chǔ)柄粹,問的也不多喘鸟,都是比較常規(guī)的,自己覺得回答都還OK驻右。另外數(shù)據(jù)庫索引方面的知識迷守,面試官問索引最優(yōu)實現(xiàn)以及給了一個場景自己判斷需不需要加索引,怎么加索引旺入,雖然自己學(xué)了兑凿,但是感覺回答的不是很好。面試時間挺短的茵瘾,自己還等了HR半個小時礼华,后來HR說初始先這樣吧,我覺得應(yīng)該是沒戲了,畢竟HR都沒面颂跨。感覺自己還是需要多出去面試一下戚揭,刷下經(jīng)驗。