IOC容器的依賴注入
IOC的依賴注入(原始碼分析)
前面的IOC容器的初始化,已經完成了BeanDefination
的資料對映,將BeanDefination
設定beanDefinitionMap
中,現在資料已經有了,但是還沒有注入到容器中,下面看下如何進行注入。
依賴注入過程:
在前面的BeanFactory
介面中經常看到getBean()
方法,現在看下在AbstractBeanFactory
中對getBean()
的具體實現:
AbstractBeanFactory#getBean()
入口
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
首先getBean都是委託doGetBean方法來實現的,在Spring的原始碼中有很多很多這種方式,我們可以在實際專案應用中來借鑑。(我們主要看主線,我這邊會將一些引數的校驗以及丟擲的異常省略,有興趣的朋友可以進原始碼詳細看)
protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
//先從快取中獲取bean,處理那些已經被建立過的bean,避免重複建立bean。
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//此處省去日誌的列印...
//完成對FactoryBean的相關處理取得FactoryBean物件,後續會詳細解釋FactoryBean。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//判斷是否已經建立過bean,如果建立過則丟擲異常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//判斷bean是夠在當前的BeanFactory中,如果不在則到雙親的BeanFactory中去獲取,如果雙親沒有,則一直往上去找。
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
//標記bean為已建立bean
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
//根據beanName獲取BeanDefination
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//獲取當前bean的所有的依賴bean,如果有依賴,則會進行遞迴呼叫getBean方法,遞迴建立依賴的bean物件。
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
//如果是迴圈依賴,則丟擲異常(省去異常資訊...)
}
//註冊依賴bean
registerDependentBean(dep, beanName);
getBean(dep);
}
}
//建立bean例項,主要是通過createBean方法來處理,後面會單獨拿出來看。
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
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 {
//其他模式下的bean的建立
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
//....異常
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
//....非法異常
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
//檢測建立的bean的型別
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
//....log
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
AbstractAutowireCapableBeanFactory#createBean()
建立bean例項
/**
* Central method of this class: creates a bean instance,
* populates the bean instance, applies post-processors, etc.
* 此類的主要方法:建立Bean例項,填充bean例項,應用後置處理bean等等
* @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.
// 通過類裝載器來載入bean
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
//校驗當前的bean使用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.
//為BeanPostProcessors提供返回代理而不是目標bean例項的機會
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建立的呼叫,實際的處理還是委託doCreateBean()方法來處理
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);
}
}
AbstractAutowireCapableBeanFactory#doCreateBean()
建立bean例項
/**
* Actually create the specified bean. Pre-creation processing has already happened
* at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
* <p>Differentiates between default bean instantiation, use of a
* factory method, and autowiring a constructor.
* @param beanName the name of the bean
* @param mbd the merged bean definition for the bean
* @param args explicit arguments to use for constructor or factory method invocation
* @return a new instance of the bean
* @throws BeanCreationException if the bean could not be created
* @see #instantiateBean
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
*/
//實際建立bean的地方,此時預處理已經完成了。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 持有例項化的bean
BeanWrapper instanceWrapper = null;
//如果是單例,則刪除快取中的這個beanName例項
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//建立bean例項
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//拿到此物件包裝的bean的例項
final Object bean = instanceWrapper.getWrappedInstance();
//拿到此物件包裝的bean的型別
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
//允許後處理器修改合併的bean定義。
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.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
//初始化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);
}
}
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);
}
}
//省去實際依賴bean為空的異常處理...
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
大致可以理一下,與依賴注入有關的比較重要的方法createBeanInstance
、populateBean
。
-
createBeanInstance
建立bean的例項,生成了Bean所包含的所有的物件。下面看下原始碼:/** * Create a new instance for the specified bean, using an appropriate instantiation strategy: * factory method, constructor autowiring, or simple instantiation. * @param beanName the name of the bean * @param mbd the bean definition for the bean * @param args explicit arguments to use for constructor or factory method invocation * @return a BeanWrapper for the new instance * @see #obtainFromSupplier * @see #instantiateUsingFactoryMethod * @see #autowireConstructor * @see #instantiateBean */ protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // Make sure bean class is actually resolved at this point. //確認建立的bean例項可以例項化。 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()); } //Spring 5.0 新增的例項化策略,如果設定了該策略,將會覆蓋構造方法和工廠方法例項化策略 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } //如果工廠不為空,則使用工廠方法對Bean進行例項化 if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } // Shortcut when re-creating the same bean... // 當建立一個相同的bean時,使用之間儲存的快照 // 這裡可能會有一個疑問,什麼時候會建立相同的bean呢? //單例模式: Spring不會快取該模式的例項,那麼對於單例模式的bean,什麼時候會用到該例項化策略呢? //我們知道對於IoC容器除了可以索取bean之外,還能銷燬bean,當我們呼叫xmlBeanFactory.destroyBean(myBeanName,myBeanInstance), //銷燬bean時,容器是不會銷燬已經解析的建構函式快照的,如果再次呼叫xmlBeanFactory.getBean(myBeanName)時,就會使用該策略了. // ③-->② 原型模式: 對於該模式的理解就簡單了,IoC容器不會快取原型模式bean的例項,當我們第二次向容器索取同一個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);
相關推薦
Spring Ioc容器依賴注入
1、時序圖 IOC容器的依賴注入是建立在資料BeanDefinition準備好的前提之下的。依賴注入的發生有兩種情況:系統第一次向容器索要bean的時候;bean在配置的時候設定了Lazy-init屬性,該屬性會讓容器完成預例項化,預例項化就是一個依賴注入的過程。Bean
SpringBoot啟動流程分析(六):IoC容器依賴注入
SpringBoot系列文章簡介 SpringBoot原始碼閱讀輔助篇: Spring IoC容器與應用上下文的設計與實現 SpringBoot啟動流程原始碼分析: SpringBoot啟動流程分析(一):SpringApplication類初始化過程 SpringBoot啟動流程分析(二)
深入理解spring容器中的控制反轉(IOC)和依賴注入(DI)
首先在開篇之前我們一定一定要明確的就是:DI和IOC並不是兩個概念,DI是IOC思想在應用上的具體例子。 什麼是控制反轉(IOC)? “控制”就是指一件事物對另一件事物進行一種管理,而另一件事物處在一件事物的管理之下,這就叫控制。 在面向物件程式設計的時候,每一個程式的
Spring IOC原始碼詳解之容器依賴注入
進入BeanWrapperImpl public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements BeanWrapper BeanWrapperImpl繼承了AbstractNestablePropert
1.Spring、IOC與依賴注入
Spring概述 Spring是分層的Java SE/EE應用 full-stack輕量級開源框架,以IoC(Inverse Of Control:反轉控制)和 AOP(Aspect Oriented Programming:面向切面程式設計)為核心,提供了展現層Spr
Spring基於註解 的IOC的依賴注入
新建 project maven## 標題 初識 註解的 開發 是:將 熟悉的 xml 結合的 完成學習的 –>(需要官方的文件支援 沒有:不能執行) 》AOPjar包 的 -----xml 的配置–告知Spring要掃描的 包 xml 約束 檔案 ----
單元測試(Junit)使用及Junit支援Spring IOC的依賴注入
單元測試在我們日常寫程式碼的過程中特別重要,可以儘快發現區域性的程式碼問題 Junit是我經常使用的一種單元測試工具 下面先寫一個單元測試的示例 先寫一個提供呼叫方法的類 package test; /** * @author coder * @version v
IOC容器和注入方式
IOC和DI IOC: 反轉資源獲取的方向 DI: IOC的另一種表述反式,即元件以一些預先定義好的方式(例如:setter方法)接收來自如容器的資源注入 IOC容器物件的關聯關係 IOC前生--分離介面與實現 IOC前生--採用工廠設計模式 IOC前生--採用反轉控制 配置Bean
Spring的控制反轉IOC和依賴注入DI
首先想說說IoC(Inversion of Control,控制反轉)。這是spring的核心,貫穿始終。所謂IoC,對於spring框架來說,就是由spring來負責控制物件的生命週期和物件間的關係: 誰控制誰,控制什麼:傳統Java SE程式設計,我們直接在物件內部通過new進行
控制反轉(IoC)和依賴注入(DI)
容器,字面上理解就是裝東西的東西。常見的變數、物件屬性等都可以算是容器。一個容器能夠裝什麼,全部取決於你對該容器的定義。當然,有這樣一種容器,它存放的不是文字、數值,而是物件、物件的描述(類、介面)或者是提供物件的回撥,通過這種容器,我們得以實現許多高階的功能,其中最常提到的,就是 “解耦” 、“依
控制反轉IOC的依賴注入方式 【調侃】IOC前世今生 IoC模式 談談對Spring IOC的理解 一個簡單的小程式演示Unity的三種依賴注入方式 小菜學習設計模式(五)—控制反轉(Ioc) IoC模式(依賴、依賴倒置、依賴注入、控制反轉) IoC模式
轉自:https://www.cnblogs.com/ysyn/p/5563256.html 引言: 專案中遇到關於IOC的一些內容,因為和正常的邏輯程式碼比較起來,IOC有點反常。因此本文記錄IOC的一些基礎知識,並附有相應的簡單例項,而在實際專案中再複雜的應用也只是在
AutoFac (控制反轉IOC 與依賴注入DI) 優化
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FB.CMS.Repository { usin
10、IoC之依賴注入(3)-解析注入的屬性
對於屬性注入的間接引用,具體的解析過程是在BeanDefinitionValueResolver類中的resolveValueIfNecessary方法中實現的,主要解析Array,Set,Map,props和字串型別的間接引用。具體實現原始碼如下: // BeanDe
Spring.net 控制反轉(IOC)依賴注入(DI)的使用 以及Config檔案的配置
IOC 一 、把 \Spring.Net\Spring.NET-2.0.0-M1\Spring.NET\bin\net\4.0\release下的 三個核心檔案 S
控制反轉(IoC)以及依賴注入(DI)的解釋
理解IoC和DI對於Spring的初學者來說是很重要的. 剛開始接觸到這兩個詞感覺過於抽象實在難懂,會有很多問題產生,什麼叫反轉?什麼是依賴關係,啥又叫注入? 程式設計師都是懶惰和高冷的 記住這句話,因此一個純粹的程式設計師都會想方設法讓自己的程式碼變得簡潔,並且後期修改的
AutoFac IoC DI 依賴注入
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Optim
Spring框架學習筆記(1)——控制反轉IOC與依賴注入DI
Spring框架的主要作用,就是提供了一個容器,使用該容器就可以建立並管理物件。比如說Dao類等,又或者是具有多依賴關係的類(Student類中包含有Teacher類的成員變數) Spring有兩個核心概念,一個是控制反轉(IOC,全稱為Inverse of Control),另一個則是面向切面程式設計(AO
.NET IoC模式依賴反轉(DIP)、控制反轉(Ioc)、依賴注入(DI)
# 依賴倒置原則(DIP) 依賴倒置(Dependency Inversion Principle,縮寫DIP)是面向物件六大基本原則之一。他是指一種特定的的解耦形式,使得高層次的模組不依賴低層次的模組的實現細節,依賴關係被顛倒(反轉),從而使得低層次模組依賴於高層次模組的需求抽象. 該原則規定: -
SpringFramework的核心:IOC容器的實現------IoC容器的依賴注入
如果IoC容器已經載入了使用者定義的Bean資訊,並開始分析依賴注入的原理。依賴注入是使用者第一次向IoC容器索要Bean時觸發的,當然也有例外。如果我們設定了lazy-init的屬性。是可以在剛開始初始化容器的時候就為我們生成新的bean。 首先我們從DefaultListableBean
4. IOC容器的依賴注入(原始碼解讀)
一、基本概念 1.當Spring IoC容器完成了Bean定義資源的定位、載入和解析註冊以後,IoC容器中已經管理類Bean定義的相關資料,但是此時IoC容器還沒有對所管理的Bean進行依賴注入,依賴注入在以下兩種情況發生: (1)使用者第一次通過getBean