1. 程式人生 > >Java框架之Spring01-IOC-bean配置-檔案引入-註解裝配

Java框架之Spring01-IOC-bean配置-檔案引入-註解裝配

Spring

 框架,即framework。是對特定應用領域中的應用系統的部分設計和實現的整體結構。就相當於讓別人幫你完成一些基礎工作,它可以處理系統很多細節問題,而且框架一般是成熟,穩健的。

 Spring概述

   Spring是一個IOC(DI)和AOP容器框架

   Spring的優良特性

     ①   非侵入式:基於Spring開發的應用中的物件可以不依賴於Spring的API

     ②   依賴注入:DI——Dependency Injection,反轉控制(IOC)最經典的實現。

     ③   面向切面程式設計:Aspect Oriented Programming——AOP

     ④   容器:Spring是一個容器,因為它包含並且管理應用物件的生命週期

     ⑤   元件化:Spring實現了使用簡單的元件配置組合成一個複雜的應用。在 Spring 中可以使用XML和Java註解組合這些物件。

     ⑥  一站式:在IOC和AOP的基礎上可以整合各種企業應用的開源框架和優秀的第三方類庫(實際上Spring 自身也提供了表述層的SpringMVC和持久層的Spring JDBC)。

 Spring模組

 IOC和DI

 IOC(Inversion of Control):反轉控制

   反轉了資源的獲取方向——改由容器主動的將資源推送給需要的元件,開發人員不需要知道容器是如何建立資源物件的,只需要提供接收資源的方式即可。這種行為也稱為查詢的被動形式。

 DI(Dependency Injection):依賴注入

   即元件以一些預先定義好的方式(例如:setter 方法)接受來自於容器的資源注入。

   總結: IOC 就是一種反轉控制的思想, 而DI是對IOC的一種具體實現。

IOC容器在Spring中的實現

  匯入Spring框架jar包

  建立配置檔案,常用檔名:applicationContext.xml或beans.xml

  • Spring中有IOC思想,  IOC思想必須基於 IOC容器來完成, 而IOC容器在最底層實質上就是一個物件工廠

    1)在通過IOC容器讀取Bean的例項之前,需要先將IOC容器本身例項化。

    2)Spring提供了IOC容器的兩種實現方式

  ① BeanFactory:IOC容器的基本實現,是Spring內部的基礎設施,是面向Spring本身的,不是提供給開發人員使用的。

  ② ApplicationContext:BeanFactory的子介面,提供了更多高階特性。面向Spring的使用者,幾乎所有場合都使用ApplicationContext而不是底層的BeanFactory。

ApplicationContext的主要實現類

  ClassPathXmlApplicationContext:對應類路徑下的XML格式的配置檔案

  FileSystemXmlApplicationContext:對應檔案系統中的XML格式的配置檔案

  在初始化時就建立單例的bean,也可以通過配置的方式指定建立的Bean是多例項的。

ConfigurableApplicationContext

      是ApplicationContext的子介面,包含一些擴充套件方法

      refresh()和close()讓ApplicationContext具有啟動、關閉和重新整理上下文的能力。所以要關閉ApplicationContext需要new此介面的物件呼叫close()方法

WebApplicationContext

       專門為WEB應用而準備的,它允許從相對於WEB根目錄的路徑中完成初始化工作

  從IOC容器中獲取bean,推薦同時指定bean的id值和型別

//通過在XML檔案中配置的id及class型別獲取物件
HelloWorld helloWorld = cxt.getBean("helloWorld",HelloWorld.class);

bean標籤

  bean標籤:將bean裝配到springIOC容器中 
  bean標籤中屬性
     id:物件唯一標識(可以不寫,如果書寫必須是唯一值)
       class:裝配bean的全類名

  bean子標籤

    property:為物件中的屬性賦值
      name:屬性名
      value:屬性值

    constructor-arg:通過構造器賦值 

給bean的屬性賦值

1. 通過bean的setXxx()方法賦值

2. 通過bean的構造器賦值,注意:如果構造器中引數型別相容,可能出現錯誤賦值情況。

<bean id="student" class="com.bean.Student01">
        <property name="name" value="小明"></property>
        <constructor-arg name="age" value="18"></constructor-arg>
</bean>

3. p名稱空間

<bean id="student" class="com.bean.Student01"
        p:name="小明" 
        p:age="18">
</bean>

屬性可使用的值

1. 字面量

      基本資料型別及其封裝類、String等型別都可以採取字面值注入的方式

      若字面值中包含特殊字元,可以使用<![CDATA[]]>把字面值包裹起來或轉義字元

2. null值

<property name= "bookName">
         <null/>
</property>

3. 給bean的級聯屬性賦值

  設定級聯屬性後會修改原屬性值,一般不使用

4. 外部已宣告的bean、引用其他的bean:此時value已經滿足不了需求了要用ref屬性

<bean id="school" class="com.bean.School">
        <property name="stus" ref="stu"></property>
</bean>

5. 內部bean

  當bean例項僅僅給一個特定的屬性使用時,可以將其宣告為內部bean。內部bean宣告直接包含在<property>或<constructor-arg>元素裡,不需要設定任何id或name屬性

  內部bean不能使用在任何其他地方,即不能在容器中直接獲取內部bean

為bean注入集合屬性

陣列和List:

  需要指定<list>標籤,在標籤裡包含一些元素。這些標籤可以通過<value>指定簡單的常量值,通過<ref>指定對其他Bean的引用。通過<bean>指定內建bean。通過<null/>指定空元素。甚至可以內嵌其他集合。

  陣列的定義和List一樣,都使用<list>元素。

  配置java.util.Set需要使用<set>標籤,定義的方法與List一樣。

<bean id="shop" class="com.spring.bean.Shop" >
      <property name= "bookList">
           <!-- 以bean的引用為值的List集合 -->
           <list>
               <ref bean= "book01"/>
               <ref bean= "book02"/>
           </list>
       </property>
</bean >

Map

  通過<map>標籤定義,<map>標籤裡可以使用多個<entry>作為子標籤。每個條目包含一個鍵和一個值。

        必須在<key>標籤裡定義鍵,因為鍵和值的型別沒有限制,所以可以自由地為它們指定<value>、<ref>、<bean>或<null/>元素。

<bean id="cup" class="com.spring.bean.Cup">
    <property name="bookMap">
        <map>
           <entry key="book" value-ref="bookMap"></entry>
             <entry>
                  <key>
                      <value>bookKey01</value>
                  </key>
                  <ref bean="book01"/>
              </entry>
        </map>
    </property>
</bean>                

集合型別的bean

  將集合bean的配置提取到外面,可供其他bean引用,實現重用

 <util:list id="schoolList">
        <ref bean="stu"></ref>
</util:list>

FactoryBean

  如果需要程式設計師參與建立bean的過程之中,使用FactoryBean

  工廠bean跟普通bean不同,其返回的物件不是指定類的一個例項,其返回的是該工廠bean的getObject方法所返回的物件。

  工廠bean必須實現org.springframework.beans.factory.FactoryBean介面,並重寫3個方法

<bean id="schoolFactory" class="com.factoryBeanImpl.SchoolFactory">
</bean>

bean的作用域

  可以在<bean>元素的scope屬性裡設定bean的作用域,以決定這個bean是單例項的還是多例項的。

  singleton,是所有bean的預設作用域。注意:工廠bean是通過isSingleton()方法設定是否單例的

  當bean的作用域為單例時,Spring會在IOC容器物件建立時就建立bean的物件例項

  而當bean的作用域為prototype時,IOC容器在獲取bean的例項時建立bean的例項物件

bean的生命週期

      在配置bean時,通過init-method和destroy-method 屬性為bean指定初始化和銷燬方法

      Spring IOC容器對bean的生命週期進行管理的過程:

         ① 通過構造器或工廠方法建立bean例項

         ② 為bean的屬性設定值和對其他bean的引用

         ③ 呼叫bean的初始化方法

         ④  bean可以使用了

         ⑤ 當容器關閉時,呼叫bean的銷燬方法

<bean id="stu" class="com.bean.Student" init-method="init" destroy-method="destroy">
</bean>

   bean的後置處理器

     ① bean後置處理器允許在呼叫初始化方法前後對bean進行額外的處理

               ② bean後置處理器對IOC容器裡的所有bean例項逐一處理,而非單一例項。

     ③ bean後置處理器需要實現介面:org.springframework.beans.factory.config.BeanPostProcessor。

      在初始化方法被呼叫前後,Spring將把每個bean例項分別傳遞給上述介面的以下兩個方法:

      ●postProcessBeforeInitialization(Object bean, String beanId):初始化之前執行

      ●postProcessAfterInitialization(Object, String):初始化之後執行

   注意

     引數bean:IOC容器中建立的物件

     引數beanId:IOC容器中建立物件的beanId

引用外部檔案

  將一部分資訊提取到bean配置檔案的外部,以properties格式的屬性檔案儲存起來,同時在bean的配置檔案中引用properties屬性檔案中的內容,從而實現一部分屬性值在發生變化時僅修改properties屬性檔案即可。

1. 建立properties屬性檔案

jdbc.username=root
jdbc.password=12345
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test

2. 引入context名稱空間

3.指定properties屬性檔案的位置

<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

classpath: 引入當前專案中類路徑下的資原始檔
classpath*: 引入所專案中類路徑下的資原始檔

4.從properties屬性檔案中引入屬性值

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
        p:username="${jdbc.username}"
        p:password="${jdbc.password}"
        p:driverClassName="${jdbc.driverClass}"
        p:url="${jdbc.url}">
</bean>

自動裝配

      手動裝配:在XML配置檔案中以value或ref的方式明確指定屬性值都是手動裝配。

      自動裝配:根據指定的裝配規則,不需要明確指定,Spring容器會自動將匹配的屬性值注入bean中。

      注意:自動裝配屬性的資料型別,只能是[非字面量]值。[字面量]值不能自動裝配。即基本資料型別(包裝類)+String型別都不可自動裝配

 裝配方式

  1.  根據型別自動裝配:將型別匹配的bean作為屬性注入到另一個bean中。當有多個與目標bean型別一致將報錯
  2.  根據名稱自動裝配:必須將目標bean的名稱和屬性名設定的完全相同
  3. 通過構造器自動裝配:當bean中存在多個構造器時,此種自動裝配方式將會很複雜。不推薦使用。

 基於xml,自動裝配(不推薦)

   在bean中新增autowire="byName|byType"

<bean id="student" class="com.springdemo.autowired.Student" autowire="byType"></bean>

  byName:通過類中的屬性名與bean中id(IOC容器中的id匹配)。
  * 如果數值一致,匹配成功。 如果不一致,裝配失敗(不會報錯,裝配null值)

  byType:通過類中的屬性型別與bean中的class匹配
  * 如果一致,匹配成功。
  * 如果未找到匹配型別,裝配失敗(裝配null值)
  * 如果匹配到多個相容型別(父子關係:裝配失敗,結果會報錯)

 基於註解,自動裝配bean

   需在XML文件中先新增掃描元件標籤,指定需被裝配bean的package

<context:component-scan base-package="com.bookStore" use-default-filters="true"></context:component-scan>

 

  base-package:Spring容器會掃描這個基類包及其子包中的所有類。當需要掃描多個包時可以使用逗號分隔。

  如果僅希望掃描特定的類而非基包下的所有類,可使用resource-pattern屬性過濾特定的類

  use-default-filters="true":預設元件掃描(掃描當前base-package下的包及其子包),false:不掃描...

通過子標籤控制包含與排除

  <context:include-filter>包含掃描,掃描指定匹配規則下的包及其子包

    注意:通過將use-default-filters屬性設定為false,禁用預設過濾器,然後掃描的就只是include-filter中的規則指定元件了    

  <context:exclude-filter>排除掃描,子節點表示要排除在外的目標類

    注意:將use-default-filters屬性設定為true或預設

過濾表示式,指定型別

類別

示例

說明

annotation

com.XxxAnnotation

過濾所有標註了XxxAnnotation的類。這個規則根據目標元件是否標註了指定型別的註解進行過濾。

assignable

com.BaseXxx

過濾所有BaseXxx類的子類。這個規則根據目標元件是否是指定型別的子類的方式進行過濾。

aspectj

com.*Service+

所有類名是以Service結束的,或這樣的類的子類。這個規則根據AspectJ表示式進行過濾。

regex

com\.anno\.*

所有com.anno包下的類。這個規則根據正則表示式匹配到的類名進行過濾。

custom

com.XxxTypeFilter

使用XxxTypeFilter類通過編碼的方式自定義過濾規則。該類必須實現org.springframework.core.type.filter.TypeFilter介面

 

4個註解:

  1) 普通元件:@Component

  2) 表述層控制器元件:@Controller

  3) 業務邏輯層元件:@Service

  4) 持久化層元件:@Repository

  元件命名規則

         ①預設情況:使用元件的簡單類名首字母小寫作為bean的id

    ②使用元件註解的value屬性指定bean的id:  @Component(value="指定id名")

自動裝配bean中的屬性

實現原理

  在指定要掃描的包時,<context:component-scan> 元素會自動註冊一個bean的後置處 理器:AutowiredAnnotationBeanPostProcessor的例項。該後置處理器可以自動裝配標記 了@Autowired、@Resource或@Inject註解的屬性。

@Autowired

  注入方式:既不是set注入,也不是構造注入。本質:是通過反射注入。

  自動裝配規則 

    優先使用byType進行裝配,如果能唯一匹配,則裝配成功。
    如果匹配到多個相容型別的bean,再照byName方式匹配(進行唯一篩選)
    如果通過byName唯一確定bean,則裝配成功,否則裝配失敗。

  構造器、普通欄位(即使是非public)、一切具有引數的方法都可以使用@Autowired註解

  若某一屬性允許不被裝配,可以設定@Autowired註解的required屬性為 false

    required:預設值是true,必須裝配該bean

    required值為false時,如果IOC容器中存在該bean,則裝配。如果沒有,則不裝配。

  @Autowired註解也可以應用在陣列型別的屬性上

  @Autowired註解也可以應用在集合屬性上,此時Spring讀取該集合的型別資訊,然後自動裝配所有與之相容的bean。

  @Autowired註解用在java.util.Map上時,若該Map的鍵值為String,那麼 Spring將自動裝配與值型別相容的bean作為值,並以bean的id值作為鍵。

@Qualifier

  必要時,可以組合使用@Qualifier(value="userDaoMyBatisImpl")註解指定beanId名

  Spring甚至允許在方法形參上標註@Qualifiter註解以指定注入bean的名稱