Spring核心容器


一. IOC和DI基礎


   IOC-Inversion of Control,譯為控制反轉,是一種遵循依賴倒置原則的代碼設計思想。

  所謂依賴倒置,就是把原本的高層建築依賴底層建築“倒置”過來,變成底層建築依賴高層建築。高層建築決定需要什么,底層去實現這樣的需求,但是高層並不用管底層是怎么實現的。這樣就不會出現前面的“牽一發動全身”的情況。
  而控制反轉就是把傳統程序中需要實現對象的創建、代碼的依賴,反轉給一個專門的"第三方"即容器來實現,即將創建和查找依賴對象的控制權交給容器,由容器將對象進行組合注入,實現對象與對象的松耦合,便於功能的復用,使程序的體系結構更靈活。

  

  DI-Dependency Injection,譯為依賴注入,實際上是對Ioc的另一種稱呼。2004年,大師級人物Martin Fowler為“控制反轉”取了一個更合適的名字“依賴注入”。給出了實現IOC的方法:注入。所謂依賴注入,就是由IOC容器在運行期間,動態地將某種依賴關系注入到對象之中。

  理解IOC和DI的關鍵:

  控制反轉,誰控制了誰?--IOC容器控制了對象;控制了什么?--控制了外部資源的獲取(對象,文件等);哪些方面的控制被反轉了?--獲得依賴對象的過程被反轉了。

  依賴注入,誰依賴誰?--程序依賴IOC容器;為什么需要依賴?--程序需要IOC容器來提供外部資源;誰注入誰?--IOC容器向程序注入;注入了什么?--注入某個對象所需要的外部資源。

  依賴注入(DI)和控制反轉(IOC)是從不同的角度的描述的同一件事情,就是指通過引入IOC容器,利用依賴關系注入的方式,實現對象之間的解耦。

二.  Spring容器與Bean


1. spring核心容器  

spring的核心容器包括了:Beans、Core、Context、SpEL


    ① core和beans模塊提供了整個框架最基礎的部分,包括了IOC和DI。

    ② Context建立在Core和Beans模塊提供的基礎之上:他提供了框架式訪問對象的方式

    ③ core、beans、context構成了Spring的骨架

    ④ SpEL:提供了一種強大的用於在運行時操作對象的表達式語言

 org.springframework.beans.factory.BeanFactory是Spring容器的實際代表者,容器負責容納此前所描述的bean,並對bean進行管理。

2. spring與bean的關系

  Spring容器是Spring的核心,一切SpringBean都存儲在Spring容器內。可以說bean是spring核心中的核心。Bean配置信息定義了Bean的實現及依賴關系,Spring容器根據各種形式的Bean配置信息來創建Bean實例,並調用Bean實例的方法來完成“依賴注入”,可以把Spring容器理解成一個大型工廠,Bean就是該工廠的產品,工廠(Spirng容器)里能生產出來什么樣的產品(Bean),完全取決於配置文件中的配置。而這個配置是由開發人員創建和維護的。

3. Bean的作用域 

  spring的作用域有singleton,prototype,request,session,globle session。

  這里只討論常用的singleton和prototype兩種作用域

  對於singleton作用域,每次請求同id的Bean都將獲得相同的實例,spring容器負責跟蹤Bean實例狀態,負責維護Bean實例的生命周期。

  對於prototype作用域,程序每次請求同id的Bean會獲得新的實例,spring容器只負責創建,一旦創建成功就撒手不管,不再管理Bean實例的生命周期,也不會維護Bean實例的狀態。

4. 容器中Bean的生命周期 

  Spring可以管理singleton作用域Bean的生命周期,Spring可以精確地知道singleton域bean何時被創建,何時初始化完成,以及容器何時准備銷毀Bean實例。對於singleton作用域的Bean,管理Bean的生命周期行為主要有兩個時機:注入依賴關系后,銷毀實例之前;具體的管理方法如下:
  Spring提供兩種方式在Bean全部屬性設置成功后執行特定行為

    使用init-method 屬性(代碼污染小)
            在類中編寫一個方法,在屬性中指定該方法在依賴關系設置完成后自動執行。
    實現InitializingBean接口(耦合較高)
            編寫afterPropertiesSet()方法的具體實現

  同理,若在Bean銷毀之前,執行特定的方法,只需要使用 destroy-method屬性或實現DisposableBean接口(實現destroy()方法)

  對於prototype作用域的Bean,Spring容器只負責Bean的創建,當容器創建實例完成后,Bean將完全交給客戶端代碼管理,容器不再負責其生命周期,Spring容器本身也不知道自己創建了多少個實例,更無從知道這些實例什么時候才會被銷毀。

5. Bean標簽屬性  

  ① id屬性:Bean的名稱在IOC容器中必須是唯一的。

  ② class屬性:指定Bean對應實現類的全類名,即包名加類名,必須有無參構造。

  ③ scope屬性: 前面提到過的作用域屬性,不指定默認為singleton,即單實例模式。

  ④ name屬性:設置<bean>標簽的別名,多個別名之間用逗號或空格分開。

  ⑤ parent屬性:子類Bean定義它所引用它的父類Bean。子類Bean定義它所引用它的父類Bean。這時前面的class屬性失效。子類Bean會繼承父類Bean的所有屬性,子類Bean也可以覆蓋父類Bean的屬性。注意:子類Bean和父類Bean是同一個Java類。

  ⑥ abstract屬性:用來定義Bean是否為抽象Bean。它表示這個Bean將不會被實例化,一般用於父類Bean,因為父類Bean主要是供子類Bean繼承使用。

  ⑦ singleton屬性:作用同③,默認為true

  ⑧ lazy-init屬性:用來定義這個Bean是否實現懶初始化。如果為“true”,它將在BeanFactory啟動時初始化所有的SingletonBean。反之,如果為“false”,它只在Bean請求時才開始創建SingletonBean。

  ⑨ autowire屬性:它定義了Bean的自動裝載方式。“no”:不使用自動裝配功能。“byName”:通過Bean的屬性名實現自動裝配。“byType”:通過Bean的類型實現自動裝配。“constructor”:類似於byType,但它是用於構造函數的參數的自動組裝。“autodetect”:通過Bean類的反省機制(introspection)決定是使用“constructor”

  ⑩ dependency-check屬性:它用來確保Bean組件通過JavaBean描述的所以依賴關系都得到滿足。在與自動裝配功能一起使用時,它特別有用。none:不進行依賴檢查objects:只做對象間依賴的檢查。simple:只做原始類型和String類型依賴的檢查。all:對所有類型的依賴進行檢查。它包括了前面的objects和simple。

  ⑪ depends-on屬性:這個Bean在初始化時依賴的對象,這個對象會在這個Bean初始化之前創建。

  ⑫ init-method屬性:用來定義Bean的初始化方法,它會在Bean組裝之后調用。它必須是一個無參數的方法。

  ⑬ destroy-method屬性:用來定義Bean的銷毀方法,它在BeanFactory關閉時調用。同樣,它也必須是一個無參數的方法。它只能應用於singletonBean。

  ⑭ factory-method屬性:定義創建該Bean對象的工廠方法。它用於下面的“factory-bean”,表示這個Bean是通過工廠方法創建。此時,“class”屬性失效。

  ⑮ factory-bean屬性:定義創建該Bean對象的工廠類。如果使用了“factory-bean”則“class”屬性失效。

三. spring中bean配置


 bean配置有三種方法:

1、配置形式:
①基於xml文件  ②基於注解  ③基於java類

2、配置方式:
①通過全類名(反射)
②通過工廠方法(靜態工廠方法、實例工廠方法)
③FactoryBean

3、依賴注入方式:
①屬性注入  ②構造器注入

1. 基於xml 全類名 屬性注入

    <bean id="helloWorld" class="top.arioso.spring.beans.HelloWorld"> <property name="id"> <value>123456</value> </property> <property name="age" value="18"></property> </bean> property節點:為Bean屬性賦值,name為屬性名,value對應屬性值,屬性值要有setter方法 value屬性可用子節點value替代

2. 基於xml 全類名 構造注入

    <bean id="person" class="top.arioso.spring.beans.Person"> <constructor-arg type="java.lang.String"> <value>John</value> </constructor-arg> <constructor-arg value="America" index="3"><constructor> <constructor-arg value="123456" type="int"><constructor> <constructor-arg value="man" typ><constructor> <property name="id"> <value>123456</value> </property> <property name="age" value="18"></property> </bean> 要求必須有帶參構造 根據value值匹配構造器,匹配不到就匹配下一個 可以用index屬性指定帶參構造器第幾個參數 可以用type屬性指定構造函數參數類型的匹配 value屬性可用子節點value替代

3. 基於xml 通過工廠配置

  (1) 靜態工廠方法配置

    <bean id="car" class="top.arioso.spring.factory.staticCarFactory" factory-method="getCar"> <constructor-arg value="BMW"></constructor-arg> </bean> class:工廠方法全類名 factory-method:要調用工廠方法名 若需要傳遞參數,使用constructor-arg傳值

  (2)實例工廠方法配置

    <bean id="carFactory" class="top.arioso.spring.beans.carFactory"></bean> <bean id="car" factory-bean="carFactory" factory-method="getCar"> <constructor-arg value="BMW"></constructor-arg> </bean> carFactory:工廠的實例 factory-bean: 指向工廠的實例 factory-method:要調用工廠方法名 若需要傳遞參數,使用constructor-arg傳值

  (3)通過FactoryBean配置

 spring框架自身提供的,它需要實現FactoryBean接口,實現代碼就必須寫在getObject()方法中。

    //java代碼 public class SpringFactory implements FactoryBean<Calendar>{ public SpringFactory() { System.out.println("我是一個spring工廠類"); } public Calendar getObject() throws Exception { return Calendar.getInstance(); } public Class<?> getObjectType() { return Calendar.class; } public boolean isSingleton() { return false; }
 //配置文件 <bean id="cal" class="springfactory.SpringFactory"/> 該配置返回的實例是SpringFactory的getObject方法返回的實例。

4. spring配置Bean注入

① 配置字面值
    
    可通過value屬性或<value>標簽屬性注入,
    若字面值包含特殊字符,使用<![CDATA[]]>包裹
    
    spring將屬性的空參數當空String,下面給email屬性設置了空的String值("")

 

    <bean id="nullBean" class="top.arioso.spring.NullBean"> <property name="email" value="" /> </bean>
   如果要注入null值,可以使用<null />
    <bean id="exampleBean" class="top.arioso.spring.NullBean">
        <property name="email">
            <null />
        </property>
    </bean>

② Bean之間的引用

    <bean id="dog" class="top.arioso.hello.Dog"/> <bean id="user" class="top.arioso.hello.User"> <property name="name" value="tony"/> <property name="dog" ref="dog"></property> </bean>

③ List屬性(set同理)

    <bean id="user" class="top.arioso.hello.User"> <property name="list"> <list> <value>北京</value> <value>上海</value> <value>廣州</value> <ref bean="dog"/> </list> </property> </bean>

④ map屬性

    <bean id="user" class="top.arioso.hello.User"> <property name="map"> <map> <entry key="bj" value="北京"/> <entry key="sh" value="上海"/> </map> </property> </bean>

⑤ Properties屬性

    <bean id="user" class="top.arioso.hello.User"> <property name="dbParams"> <props> <prop key="username">root</prop> <prop key="password">root</prop> </props> </property> </bean>

⑥ 獨立的集合Bean

    <util:list id="computerList"> <ref bean="computer"/> <bean class="top.arioso.spring.collection.ComputerList"> <constructor-arg value="hp"></constructor-arg> <constructor-arg value="dell"></constructor-arg> <constructor-arg value="acer"></constructor-arg> </bean> </util:list> <bean id="User" class="top.arioso.spring.User"> <property name="id" value="2018310"></property> <property name="name" value="Tom"></property> <property name="computers" value="computerList"></property> </bean>

⑦ 使用p命名空間

    <bean id="computer" class="top.arioso.spring.Computer"> <p:brand="dell" p-cpu="i7-7700" p-price="7900"> </bean> 首先需要導入命名空間

5. 基於注解配置Bean

① 注解依賴aop包,要導入aop包。

② Spring 能夠從 classpath 下自動掃描(需要配置 context:component-scan )具有特定注解的組件。

    特定的組件包括:

    @Component:基本注解,標識一個受Spring管理的組件。

    @Repository:標識持久層組件。

    @Service:標識業務層組件。

    @Controller:標識控制層組件。

   Spring 對掃描到的組件有默認的命名規則:使用非限定類名,第一個字母小寫 (也可以使用value屬性指定組件的名稱)。

③ 配置<context:component-scan>

<context:component-scan base-package="top.arioso.spring.annotation" resource-pattern="service/*.class"> </context:component-scan> base-package 屬性指定Spring掃描的包,Spring將掃描該包及其所有子包,如有多個包,使用逗號隔開。 可以使用 resource-pattern 來過濾特定的類。 <context:exclude-filter>:指定掃描排除哪些類 需設置use-default-filter為false //只掃描有Service注解的類 <context:component-scan resource-pattern="controller/*.class" base-package="top.arioso.spring.annotation" use-default-filters="false"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"> </context:component-scan> //排除掃描實現了UserRepository的類 <context:component-scan resource-pattern="controller/*.class" base-package="top.arioso.spring.annotation" use-default-filters="false"> <context:exclude-filter type="assignable" expression="top.arioso.repository.UserRepository"> </context:component-scan> <context:include-filter>:指定掃描包含哪些類 //排除掃描有Service注解的類 <context:component-scan resource-pattern="controller/*.class" base-package="top.arioso.spring.annotation" <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"> </context:component-scan> //只掃描實現了UserRepository的類 <context:component-scan resource-pattern="controller/*.class" base-package="top.arioso.spring.annotation" <context:include-filter type="assignable" expression="top.arioso.repository.UserRepository"> </context:component-scan>

6. 使用注解自動裝配Bean

①Autowired自動注入

  @Autowired可以在字段、setter方法、構造器上面使用
    
  默認情況下,當使用 @Autowired 注解的屬性,如果在IOC容器中找不到匹配的Bean來裝配屬性時,會拋出異常。可以使用required=false 設置某一屬性不被設置(即IOC容器不配置匹配的Bean)。
    
  使用@Autowired注解的屬性,當 IOC 容器中存在多個類型匹配的 Bean 時,默認情況下會匹配與屬性相同名稱的 Bean,若匹配不到則拋出異常。也可以使用 @Qualifier(“Bean名稱”) 注解指定注入的Bean。
    
  @Autowired也可以用在數組上,Spring會將所有匹配的Bean自動裝配進數組。

  @Autowired也可以用在集合上,Spring會判斷該集合的類型,然后自動裝配所有類型兼容的Bean。

  @Autowired也可以用在Map上,若key為String類型,Spring將Bean的名稱作為key,Bean本身作為值自動裝配所有類型兼容的的Bean。
     
  也可以使用 @Resource 或 @Inject 自動裝配Bean,功能與 @Autowired 類似,一般使用@Resource和@Autowired,不推薦@Inject。

②Resource自動裝配  

  @Resource與@Autowired作用類似,只不過@Autowired按ByType自動注入,Resource按ByName自動注入;

  @Resource裝配順序
  如果同時指定了name和type,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則拋出異常
  如果指定了name,則從上下文中查找名稱(id)匹配的bean進行裝配,找不到則拋出異常
  如果指定了type,則從上下文中找到類型匹配的唯一bean進行裝配,找不到或者找到多個,都會拋出異常
  如果既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配;如果沒有匹配,則回退為一個原始類型進行匹配,如果匹配則自動裝配。

③@Qualifier注解

  Qualifier譯為合格者,一般與Autowired配合使用,當有多個類實現一個借口,spring不知道綁定哪個實現類,可以用Qualifier(Bean名稱或注解名) 配合@Autowired使用

④@Autowired與@Resource的區別

  @Resource是所屬於J2EE的,而@Autowired是所屬於Spring的;

  @Autowired是默認按類型(ByType)裝配的,默認要依賴的對象必須存在,否則拋出異常,如果允許為null值,可以設置@Autowired(required=false),@Resource是默認按名稱(ByName)裝配的,如果不指定name,則把字段名當做名稱尋找,找不到與該名稱匹配的Bean時才會按類型尋找。但是一旦指定name,就會按名稱尋找,找不到拋出異常。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM