1. 程式人生 > >Spring IOC的個人理解及Spring對bean的裝配

Spring IOC的個人理解及Spring對bean的裝配

IOC是什麼?

IOC的英文全稱是Inversion of Control,即控制反轉。IOC並不是什麼技術,而是一種設計思想。

IOC有什麼好處,或者說你怎麼理解控制反轉?

這是恐怕是面試官對於Spring框架的問題中最為常見的一個問題了。
歷史遺留問題:在平時我們開發Java程式的時候,對於一個要使用的物件往往我們需要new一個出來,主動權在我們開發者的手裡,物件的建立時機往往由我們開發者決定。物件A中用到了物件B,而物件B中又用到了物件C和物件D,這樣各種各樣的相互依賴,會使程式的耦合度高了起來。
現在IOC出現了:IOC的出現就是為了解耦,它有一個專門的容器去自己建立物件,也就是說建立物件的控制權被反轉了,建立物件的時機和動作發起者從原來開發者到現在的一個第三方容器的手中。物件A、物件B、物件C、物件D他們之間的依賴關係由於容器的出現從相互依賴變成了都只依賴於容器,因為物件的例項化都是由容器去完成的,原先的物件只需要持有依賴物件的引用即可,通過這種方法去達到解耦的目的。
引用知乎大神的一句總結:
IOC的思想最核心的地方在於,資源不由使用資源的雙方管理,而由不使用資源的第三方管理,這可以帶來很多好處。
第一,資源集中管理,實現資源的可配置和易管理。
第二,降低了使用資源雙方的依賴程度,也就是我們說的耦合度。
摘抄於:

Spring IoC有什麼好處呢?
再次引用開濤大神部落格中的一句話:
IoC很好的體現了面向物件設計法則之一—— 好萊塢法則:”別找我們,我們找你”;即由IoC容器幫物件找相應的依賴物件並注入,而不是由物件主動去找。
摘抄於:【第二章】 IoC 之 2.1 IoC基礎 ——跟我學Spring3

IOC在Spring中的體現

IOC是Spring的核心,對於Spring來說,所有需要被管理起來的資源都要進行登記,你需要配置一下Spring的配置檔案,告訴Spring容器,你是什麼,你需要什麼,Spring容器會在程式執行到適當的時候給你你所要的東西,同樣的也會像這樣把你交給別人。所有物件都在Spring容器的管理之下,這些物件我們叫它bean。預設情況下Spring中定義的bean是以單例模式建立的。有預設自然就會有別的情況這就涉及到了bean的作用域了,暫且不提。Spring在程式執行時給bean提供它所需要的其他bean,這一點是通過DI來實現的。DI的英文全稱是Dependency Injection(依賴注入),是IOC的一種實現方式。建立應用物件之間協作關係的行為通常稱為裝配,這也是依賴注入的本質。那Spring是怎麼做的咧?
答案是Java的反射機制。眾所周知,Java可以通過反射將一個給出的完整類名(字串方式)來動態地生成物件。假設某個配置檔案裡面寫好了一個類的全類名,通過讀取配置檔案就能獲取到這個類的全類名,在執行時動態生成這個類,在賦值到需要的地方。這就完成了依賴注入,這也就是Spring的做法。

Spring對bean的裝配

Spring提供3種主要的裝配機制:
1.在xml中進行顯示配置
2.在Java中進行顯示配置
3.隱式的bean發現機制和自動裝配

基於XML的顯示配置——Setter注入和構造方法注入

Setter注入

Setter注入,顧名思義,被注入的屬性要有set方法。物件注入使用<property>的ref屬性。
以我之前的部落格中Spring整合shiro的配置為例。
在類ShiroDbRealm中有userService的引用,及set方法

public void setUserService(UserServiceImpl userService) {
    this
.userService = userService; }

在spring-shiro.xml配置檔案中需要如下配置才能成功注入userService。

<!-- 配置進行授權和認證的 Realm -->
<bean id="myRealm" class="com.gray.base.shiro.ShiroDbRealm">
    <property name="userService" ref="userService" />
</bean>
<bean id="userService" class="com.gray.user.service.impl.UserServiceImpl" />

當然,<property>標籤不止可以注入物件,也可以注入一些簡單的值和集合型別,普通值使用<property>標籤的value值,資料結構則需要額外加上集合型別,如:

   <property name="citys">  
       <list>  
           <value>北京</value>  
           <value>上海</value>  
           <value>深圳</value>
           <value>廣州</value>  
       </list>  
   </property> 

構造方法注入

通過構造方法注入依賴,如SqlSessionTemplate在Spring的配置檔案中是這樣宣告的:

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
          <constructor-arg index="0" ref="sqlSessionFactory" />   
          <constructor-arg index="1" value="BATCH" />  
     </bean> 

讓我們進入到SqlSessionTemplate中,配置檔案所寫的,在實際例項化SqlSessionTemplate時會呼叫兩個引數的構造方法。

public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
        this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true));
    }

而<constructor-arg>標籤中的index屬性,通過index屬性可以告訴Spring容器傳遞的依賴引數的順序。構造方法注入也和Setter注入一樣,同樣可以注入一些簡單的值和集合型別。

基於註解的注入

@Autowired
例如:

    @Autowired
    private UserDao<User> dao;

@Autowired可以用在類的任何方法上。
@Resource
由Java提供,可用於Setter方法,但是無法用於構造方法上。
@Value
可直接用於獲取被Spring管理的properties屬性檔案的值。

db.url=jdbc:mysql://127.0.0.1:3306/test

例在配置檔案中配置了引入的屬性檔案

<!-- 引入屬性檔案 -->
<context:property-placeholder location="classpath:jdbc.properties" />

使用的時候只需要這樣寫@Value("${jdbc.url}")
這三個註解,會幫我們把宣告在Spring中bean自動裝配到需要的地方。

好了,說了那麼多,一切都是要我們在XML配置檔案中設定了這些bean為前提我們才能用,應用程式裡面有那麼多類,難道我們要一一為它們都去配置檔案裡面宣告嗎?
答案是否定的,Spring為我們提供了包掃描機制
例如在配置檔案中配置了要掃描的路徑

<!-- 自動掃描(自動注入) -->
<context:component-scan base-package="要去掃描的路徑" />

在啟動的時候會根據配置檔案中配置的要掃描的路徑去掃描這些路徑中包含@Component、@Service和@Repository等(Springmvc中加上@Controller)註解的類,並自動視為已經註冊的bean,如果沒有為bean配置名稱,那Spring會給它們一個預設的名字,類名(第一個字元小寫)變成bean名稱。

總之,Spring框架強大的注入功能幫我們管理bean的生命週期,我們只需要關注怎麼使用就好了,Spring具有非常大的靈活性,在實際開發中註解和xml配合使用可以大大增加程式碼的靈活性。
以上所說的只是Spring的注入和裝配bean的一些基礎知識,但這些東西會一直伴隨著我們整個開發工作中,還是要多熟記。如果想知道Spring在初始化的時候到底還做了些什麼,具體還得去研讀一下原始碼,但在這裡就不多加敘述了。