你不知道系列--Spring IOC的祕密

什麼是IOC控制翻轉?

Spring作爲常用框架,面試的時候經常會有面試官問,Spring IOC瞭解嗎?作爲面試者回答:這個我知道,Spring IOC控制翻轉,就是把實例化的對象交給Spring容器來實始化。 面試官繼續問:哪裏說說IOC控制翻轉有什麼作用(優點),是怎麼實現的?作爲面試者:enmmmm…這個時候就很尷尬了。

任何事情不能侷限於表面,需要有求知意識,儘自己能力和理解去探求真相,當然這個也不是一蹴而就,是一個循序漸進的過程,重要的是在這條路上需要不斷求索。

瞭解Bean是如何在Spring中配置的

Bean默認是配置在applicationContext.xml文件中,那麼我們首先需要明白Spring是如何加載配置文件的,請看博文:你不知道系列–Spring是如何加載配置文件

通過博文我們會了解到Spring配置文件是如何實現加載的,Spring配置文件實例化的流程,通過依賴Servlet的創建和銷燬,來實現Soring配置文件加載和銷燬,其實ContextLoaderListener是web組件,真正實例化的是Tomcat,Tomcat在啓動加載web.xml實例化並識別Lintenter配置,Spirng是維護了ApplicationContext對象(容器對象),通過ApplicationContext對象讀取配置文件。

瞭解Bean是如何在Spring中實例化

在瞭解Spring如何加載配置文件和讀取Bean後,那麼Bean是如何進行實例化的,以及Bean的生命週期流程是什麼,請看博文:spring–Bean生命週期。

通過博文我們會了解到通過Spring維護的applicationContext對象(容器對象),可以通過getBean()來獲取指定Bean對象,是不是很神奇?,不僅如此,如果知道Bean的生命週期,我們還能再Bean實例化的各個步驟中進行動態處理。

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
}

容器對象ApplicationContext

ApplicationContext接口繼承了很多接口,這些接口我們可以將其分爲五類:

  • MessageSource,主要用於國際化
  • ApplicationEventPublisher,提供了事件發佈功能
  • EnvironmentCapable,可以獲取容器當前運行的環境
  • ResourceLoader,主要用於加載資源文件
  • BeanFactory,負責配置、創建、管理Bean,IOC功能的實現主要就依賴於該接口子類實現。

具體的接口功能,大家有興趣可以瞭解,推薦博文:https://blog.csdn.net/qq_41907991/article/details/104890350

應該如何理解Spring核心思想IOC控制翻轉:

對象的創建交給外部容器完成,這個就做控制反轉。

  • Spring使用控制反轉來實現對象不用在程序中寫死
  • 控制反轉解決對象處理問題【把對象交給別人創建】

如何理解DI,是如何處理對象之間的依賴問題:

  • Spring使用依賴注入來實現對象之間的依賴關係
  • 在創建完對象之後,對象的關係處理就是依賴注入

IOC和DI關係

IoC 全稱爲 Inversion of Control,翻譯爲 “控制反轉”,它還有一個別名爲 DI(Dependency Injection),即依賴注入。
DI—Dependency Injection,即“依賴注入”:是組件之間依賴關係由容器在運行期決定,形象的說,即由容器動態的將某個依賴關係注入到組件之中。依賴注入的目的並非爲軟件系統帶來更多功能,而是爲了提升組件重用的頻率,併爲系統搭建一個靈活、可擴展的平臺。通過依賴注入機制,我們只需要通過簡單的配置,而無需任何代碼就可指定目標需要的資源,完成自身的業務邏輯,而不需要關心具體的資源來自何處,由誰實現。

理解DI依賴注入

  • Spring使用依賴注入來實現對象之間的依賴關係(實際開發中我們常用的@Autowired註解標註在對象屬性上,實際就是提供了對象屬性的Set方法)
  • 在創建完對象之後,對象的關係處理就是依賴注入

Srping如何處理Bean的屬性注入

  • 有參構造注入
  • set方法注入

總結:
所謂 IOC ,就是由 Spring IOC 容器來負責對象的生命週期和對象之間的關係。

來段代碼看看沒有IOC容器進行屬性注入

  • 定義一個水果類接口
public interface Fruit {

	public void get();

}
  • 實現水果的類,具體水果
public class Apple implements Fruit {

	public void get() {
		// TODO Auto-generated method stub
		System.out.println("拿到蘋果!!!");
	}

}



public class Banana implements Fruit {

	public void get() {
		// TODO Auto-generated method stub
		System.out.println("拿到香蕉!!");
	}

}
  • Service業務層,這裏主要是體現業務邏輯
    (體現組件之間的依賴關係,對象屬性的注入)
public class UserService {

	private Fruit fruit = new Apple();

	public void getName() {
		fruit.get();
	}
}
  • 模擬用戶類調用
public class User {

	public static void main(String[] args) {
		UserService us = new UserService();
		us.getName();
	}

}

思考:

其實這一段代碼沒什麼問題,控制會輸出"拿到蘋果!!",這也符合我們代碼需求,但是水果的實現不止一種,如果我們需要香蕉呢?這個時候就需要改動Service代碼,把蘋果換成香蕉,那麼每次更換都需要重新new水果對象,這樣一點都不靈活,其實我們需要思考一個問題?我們每次用到自己依賴的對象真的需要自己去創建嗎?我們知道,我們在UserService依賴的Fruit對象其實並不是依賴該對象本身,而是依賴它所提供的服務(不同水果對象,提供不同的水果),只要在我們需要它的時候,它能夠及時提供服務即可,至於它是我們主動去創建的還是別人送給我們的,其實並不是那麼重要。再說了,相比於自己千辛萬苦去創建它還要負責初始化、管理使用、銷燬等方法而言,直接有人送過來是不是顯得更加好呢?
IOC就是給我們送東西過來的人,或者理解稱爲中介,需要什麼直接找到IOC容器,用戶需要蘋果,並不需要直接創建蘋果,而是開放程序接口,由IOC容器進行注入。
IOC的思想最核心的地方在於,資源不由使用資源的雙方管理,而由不使用資源的第三方管理,這可以帶來很多好處。第一,資源集中管理,實現資源的可配置和易管理。第二,降低了使用資源雙方的依賴程度,也就是我們說的耦合度。

再來段代碼看看IOC容器,通過set屬性注入後的變化

  • 在Service業務層依賴水果類,我們給水果類提供了Set方法進行屬性注入
public class UserService {

	private Fruit fruit;

	public void getName() {
		fruit.get();
	}
	public void setFruit(Fruit fruit) {
		this.fruit = fruit;
	}

}
  • 模擬用戶調用,這時我們需要什麼水果權限,就給到用戶來決定(控制權限翻轉)。
public class User {

	public static void main(String[] args) {
		UserService us = new UserService();
		us.setFruit(new Banana());
		us.getName();
	}

}

最後總結一下使用IOC的好處:

  • 不用自己組裝,拿來就用。
  • 享受單例的好處,效率高,不浪費空間。
  • 便於單元測試,方便切換mock組件。
  • 便於進行AOP操作,對於使用者是透明的。
  • 統一配置,便於修改。
    Spring IOC容器和DI(依賴注入的)是相輔相成的關係,通過組件或對象的注入實現對象創建,不需要用戶親自管理組件或對象的組合裝配,這些都交給IOC容器進行管理,需要什麼從資源管理的第三方IOC容器獲取,用戶只需要專注自己的業務邏輯。

希望幫助大家更熟悉Spring IOC的原理和意義,請多多支持我的博客!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章