IOC(Inversion Of Control),即控制反轉,或者說DI(Dependency Injection),依賴注入,都屬於Spring中的一種特色,能夠統稱爲IOCjava
不論是IOC仍是DI,它們都有一個共同的特色,即經過第三方容器來管理對象的建立、初始化、注入、銷燬,在Spring中,這些容器中的對象統稱爲bean,使用的時候只須要經過xml或Java的配置就可以很方便地將一個對象聲明爲容器中的bean,而且能夠經過@Autowired註解等方法將這些bean注入到須要的地方,咱們接下來就要深刻地瞭解一下Spring中IOC究竟是怎麼實現的spring
顧名思義,BeanFactory就是Bean的工廠,也就是Bean的容器,BeanFactory做爲容器接口,咱們暫不關心它的實現類,先了解一下它自己的特性,點進BeanFactory的源碼,咱們只看如下這幾個重要的方法,其他方法用到的時候再說編程
/** 經過name獲取bean實例 */
Object getBean(String name) throws BeansException;
/** 經過name和對象類型獲取bean實例 */
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
/** 獲得bean的別名,若是經過別名索引,則原名也會被檢索出 */
String[] getAliases(String name);
複製代碼
這幾個方法看起來很簡單,別急,這只是在接口中的定義,Spring提供了不少BeanFactory的實現類,好比ApplicationContext等緩存
bean固然不能用普通的對象來描述,在spring中,bean被封裝成BeanDefinition,以下: 安全
資源的加載,也能夠是認爲是容器的初始化,能夠分爲如下三個部分:session
好比XmlWebApplicationContext就是從xml文件中加載資源,咱們這裏以ClassPathXmlApplicationContext爲例,瞭解一下xml文件中的配置是怎麼加載到Spring容器中的多線程
首先是構造方法,以下:併發
/** * @param configLocations 資源路徑 * @param refresh 是否自動刷新容器 * @parent parent 容器的父類 */
public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
複製代碼
先來看這個super(parent),咱們一路找上去,發現每一層都調用了super(parent),直到進入AbstractApplicationContext類中,發現調用了一個this()方法,這個方法詳細以下:app
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
複製代碼
從字面上理解,應該是相似設置資源解析器之類的方法,咱們進入這個方法,發現其實際上建立了一個PathMatchingResourcePatternResolver對象,同時設置咱們的最頂層容器爲resourceLoader資源加載器,看到這裏就差很少了解了,super(parent)實際上就是設置了bean的資源加載器ide
咱們接着看setConfigLocations(configLocations)方法,源碼以下:
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
複製代碼
這個方法是繼承而來的,是AbstractRefreshableConfigApplicationContext的一個方法,在這個方法內部,設置了configLocations的值爲資源路徑(進行環境變量填補充並去除空格),能夠理解爲對資源進行定位
也就是說,容器在建立出來時,作了如下兩件事(不包括刷新容器操做):
而後咱們再來看這個可選的refresh()方法,這是從AbstractApplicationContext繼承而來的方法,源碼以下:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 獲取當前時間,同時設置同步標識,避免多線程下衝突
prepareRefresh();
// 實際調用了子類的refreshBeanFactory方法,同時返回子類的beanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 設置容器屬性
prepareBeanFactory(beanFactory);
try {
// 爲子類beanFactory指定BeanPost事件處理器
postProcessBeanFactory(beanFactory);
// 調用註冊爲bean的事件處理器
invokeBeanFactoryPostProcessors(beanFactory);
// 註冊BeanPost事件處理器,用於監聽容器建立
registerBeanPostProcessors(beanFactory);
// 初始化消息源
initMessageSource();
// 初始化事件傳播器
initApplicationEventMulticaster();
// 在特定的子類中初始化其餘特殊的bean
onRefresh();
// 檢查並註冊監聽器
registerListeners();
// 初始化剩餘的單例
finishBeanFactoryInitialization(beanFactory);
// 最後一步:初始化容器生命週期處理器,併發布容器生命週期事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 銷燬建立的單例,以免懸置資源
destroyBeans();
// 重置同步標識
cancelRefresh(ex);
throw ex;
}
finally {
// 由於不須要單例bean中元數據,因此重置spring的自檢緩存
resetCommonCaches();
}
}
}
複製代碼
配合註釋,就能差很少了解了執行過程,實際就是初始化並註冊一系列處理器和監聽器的過程,有人可能會發現,怎麼沒有加載資源的過程,別急,咱們進入obtainFreshBeanFactory()方法,其中有一個refreshBeanFactory()方法,咱們點開AbstractRefreshableApplicationContext中的實現:
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
複製代碼
發現了嗎,這裏有一個loadBeanDefinitions()方法,會根據選用的xml解析仍是註解解析調用子類中的方法,再接下來的解析過程就不是咱們分析的重點了,若是之後有時間,我會再寫一篇來專門分析解析過程的文章
到這裏,整個加載過程就清晰了
一開始,咱們就介紹了getBean(name)方法,那麼咱們接下來,就要詳細的來進行分析這個方法究竟是怎麼把咱們須要的bean建立並交給咱們的
這個方法有兩種常見的實現,AbstractBeanFactory和AbstractApplicationContext,而實際上AbstractApplicationContext也是調用了AbstractBeanFactory的方法,因此咱們就只看AbstractBeanFactory便可
在這個方法內部調用了doGetBean方法,咱們進入方法內部,以下:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
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) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current 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.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 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;
}
複製代碼
整個方法至關之長,咱們分部分來看,先來看第一部分:
// 轉換爲規範名稱(主要針對別名)
final String beanName = transformedBeanName(name);
Object bean;
// 檢查緩存,避免重複建立單例
Object sharedInstance = getSingleton(beanName);
// 若是不爲空,就返回緩存中的單例
if (sharedInstance != null && args == null) {
// 若是開啓了trace日誌,就根據當前的狀態打印日誌
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 從緩存中返回
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
複製代碼
這個部分至關於一個預檢操做,若是緩存中已經有單例了,就直接返回,避免重複建立
接下來就是真正的建立過程,以下
else {
// 發現bean正在被建立,說明緩存中已經有原型bean,
// 多是因爲循環引用致使,這裏拋出異常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 查找容器中是否有指定bean的定義
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// ...
}
// 判斷是否須要類型驗證,這個值默認爲false
if (!typeCheckOnly) {
// 在容器中標記指定的bean已經被建立
markBeanAsCreated(beanName);
}
try {
// 獲取父級bean定義,合併公共屬性
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 獲取bean的依賴,保證其依賴的bean提早被正常的初始化
String[] dependsOn = mbd.getDependsOn();
// 若是依賴有其餘bean,就先初始化其依賴的bean
if (dependsOn != null) {
// ...
}
// 以單例模式建立
if (mbd.isSingleton()) {
// ...
}
// 以原型模式建立
else if (mbd.isPrototype()) {
// ...
}
// 若是是其餘模式,就用bean定義資源中配置的生命週期範圍(request、session、application等)
else {
// ...
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
複製代碼
配合註釋,核心部分分爲如下幾個小部分:
這樣一看好像很簡單,確實如此,若是你僅僅是想了解一個大體的建立過程,接下來的部分能夠略過,直接進入下一部分,若是你想詳細地瞭解整個建立過程,那麼就請跟着我再進一步分析在代碼中省略的部分
// 查找容器中是否有指定bean的定義
BeanFactory parentBeanFactory = getParentBeanFactory();
// 若是當前容器中不存在bean的定義,且父容器不爲空,就進入父容器中查找
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
String nameToLookup = originalBeanName(name);
// 若是父容器是AbstractBeanFactory,說明已經到最頂層容器了,
// 直接調用其doGetBean方法
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
// 若是指定參數,就根據顯式參數查找
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
// 若是沒有指定參數,就根據指定類型名查找
else if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
// 不然就採用默認查找方式
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
複製代碼
查找bean定義的過程其實是一個遞歸的操做,若是子類中不存在bean定義,就從父類中尋找,若是父類不存在,就去父類的父類中尋找,...,直到抵達最頂層的父類
// 獲取bean的依賴,保證其依賴的bean提早被正常的初始化
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方法建立依賴的bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
複製代碼
這個方法沒什麼好說的,配合註釋應該能很輕鬆地看懂,重點是其中包含一個檢查循環依賴的過程
接下來就是整個方法的核心了,這裏的三種建立模式大同小異,這裏只講最經典的單例模式,其他建立模式能夠自行查閱
// 以單例模式建立
if (mbd.isSingleton()) {
// 建立單例對象
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// 從緩存中刪除單例,同時刪除接收到該bean臨時引用的bean
destroySingleton(beanName);
throw ex;
}
});
// 獲取給定的bean的實例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
複製代碼
整個方法看起來很是清晰,很好理解,無非就是建立單例,而後返回(不理解‘()->{}’這樣的lambda表達式的,能夠參考個人上一篇博文:函數式編程——Java中的lambda表達式)
這段代碼雖然短,可是包含了整個方法中核心的內容:建立bean實例,咱們點進createBean方法,這是一個抽象方法,實現部分在AbstractAutowireCapableBeanFactory中,具體源碼以下:
@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;
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.isTraceEnabled()) {
logger.trace("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);
}
}
複製代碼
看起來很是臃腫,爲了便於分析,咱們把日誌和異常都刪掉,再來看:
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
// 判斷給定的bean是否能夠被實例化(便是否能夠被當前的類加載器加載)
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
// 若是不能夠,就委派給其父類進行查找
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// 準備覆蓋bean中的方法
mbdToUse.prepareMethodOverrides();
// 若是設置了初始化先後的處理器,就返回一個代理對象
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
// 建立bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
複製代碼
是否是一會兒就簡單了不少,這也是分析源碼經常使用的方式,能夠更方便地理解程序結構。好了很少說,咱們看這段程序,首先是傳入了三個參數:bean名稱、父類bean,以及參數列表,而後就是一些常規操做,咱們這裏只看核心方法,發現實際這裏並無建立bean的代碼,畢竟連new都沒有,別急,點進doCreateBean方法,接着看:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 移除緩存(單例模式的一種實現方式)中beanName的映射,並返回這個bean
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 若是緩存中沒有該bean,就建立該bean的實例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 對bean進行封裝
final Object bean = instanceWrapper.getWrappedInstance();
// 獲取bean類型
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 對後置處理器加同步鎖
// 容許後置處理器修改合併後bean定義
synchronized (mbd.postProcessingLock) {
// 判斷後置處理器是否處理完成,若是沒有就進行【合併bean定義】後的處理操做
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.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 讓容器儘早持有對象的引用,以便於依賴對象的循環引用
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 初始化bean實例,實際觸發依賴的地方
Object exposedObject = bean;
try {
// 用參數填充bean實例
populateBean(beanName, mbd, instanceWrapper);
// 初始化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);
}
}
// 父類是單例對象 && 該bean容許循環引用 && 該bean正在建立
if (earlySingletonExposure) {
// 獲取已註冊的單例bean
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 若是已註冊的bean和正在建立的bean是同一個,則直接返回這個bean
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// 若是該bean依賴於其餘bean,且不容許在循環依賴的狀況下注入bean
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.");
}
}
}
}
// 添加bean到工廠中的一次性bean列表中,僅適用於單例模式
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
複製代碼
具體執行流程已經詳細地註釋在代碼中,我也不許備再複述一遍,相信認真看的都能讀懂,咱們這裏關注一個頗有意思的點,能夠發現代碼中有兩個地方涉及了bean的加載:
// ...
instanceWrapper = createBeanInstance(beanName, mbd, args);
// ...
exposedObject = initializeBean(beanName, exposedObject, mbd);
// ...
複製代碼
先來看createBeanInstance方法,這裏爲了不不少人看不下去,就不打算放源碼了,我簡單地講一下方法的流程:
確定有人會問,這個方法不是已經實例化對象了嗎,那後面的方法是幹什麼的?別急,咱們直接進入initializeBean方法中,對源碼有興趣的能夠自行查閱,我這裏也是簡要說下流程:
咱們能夠發現,在這個方法裏觸發了applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization兩個方法,從字面意思上也很好理解,就是前置處理器和後置處理器,在這兩個方法之間,調用了invokeInitMethods方法來執行初始化方法
那麼問題來了,initializeBean和createBeanInstance有什麼區別呢,不都是初始化嗎?實際上,真正實例化Java Bean的是createBeanInstance方法,而initializeBean則至關於咱們的自定義初始化操做,同時在其中也會執行一些前置處理和後置處理
createBeanInstance方法執行完,就至關於咱們簡單new出來一個對象而已,可是這個對象沒有添加事務,沒有添加aop,沒有進行url的映射等等操做,因此就須要initializeBean來進行初始化
別忘了,以前咱們說的那個特別長的doGetBean方法還沒完呢,最後還有一段,以下:
// 檢查所需類型是否與bean類型匹配(若是沒有設置檢查類型匹配,最後會進行強制類型轉換)
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;
複製代碼
依賴注入階段有點長,咱們這裏作一下總結,總共步驟以下:
我習慣把總結寫成要點的形式,由於這種方式比較清晰,因此儘可能習慣一下