1. 程式人生 > >Spring介紹及配置(XML文件配置和註解配置)

Spring介紹及配置(XML文件配置和註解配置)

處理 tis 配置文件 3.0 span 特點 inverse logging 結構

本節內容:

  • Spring介紹
  • Spring搭建
  • Spring概念
  • Spring配置講解
  • 使用註解配置Spring

一、Spring介紹

1. 什麽是Spring

Spring是一個開源框架,Spring是於2003 年興起的一個輕量級的Java 開發框架,由 RodJohnson 在其著作 Expert One-On-One J2EE Development and Design 中闡述的部分理念和原型衍生而來。它是為了解決企業應用開發的復雜性而創建的。框架的主要優勢之一就是其分層架構,分層架構允許使用者選擇使用哪一個組件,同時為 J2EE 應用程序開發提供集成的框架。Spring 使用基本的 JavaBean 來完成以前只可能由 EJB 完成的事情。然而,Spring 的用途不僅限於服務器端的開發,去開發android也可以。從簡單性、可測試性和松耦合的角度而言,任何 Java 應用都可以從 Spring 中受益。Spring 的核心是控制反轉 (IoC)和面向切面(AOP)。簡單來說,Spring 是一個分層的 JavaSE/EEfull-stack(一站式) 輕量級 開源框架。

JavaEE開發分成三層結構:

  • WEB層
  • 業務層
  • 持久層

三層架構中Spring的位置:

技術分享圖片

Spring是一個大的容器,其中裝了很多對象,之前三層架構在運行時,都需要自己來創建對象,比如在web層中需要使用service層中的,需要new。當使用了Spring之後,Spring中已經存好了項目中需要的對象。也就是在三層中,需要對象時不需要在寫new了,而是跟Spring要這個對象。

Spring是一站式框架:純Spring開發一個項目是完全沒問題的。正是因為Spring框架性質是屬於容器性質的(比如Spring之所以能處理請求,是因為容器中裝了能處理請求的框架,所以它在web層能處理請求),容器中裝什麽對象,就有什麽功能。所以可以一站式。

  • WEB層:Spring MVC
  • 業務層:Bean管理:(IoC)
  • 持久層:Spring的JDBC模板。ORM模板用於整合其他的持久層框架。

2. 為什麽要學習Spring

  • 方便解耦,簡化開發
    • Spring 就是一個大工廠,可以將所有對象創建和依賴關系維護,交給 Spring 管理
  • AOP 編程的支持
    • Spring 提供面向切面編程,可以方便的實現對程序進行權限攔截、運行監控等功能
  • 聲明式事務的支持
    • 只需要通過配置就可以完成對事務的管理,而無需手動編程
  • 方便程序的測試
    • Spring 對 Junit4 支持,可以通過註解方便的測試 Spring 程序
  • 方便集成各種優秀框架
    • Spring 不排斥各種優秀的開源框架,其內部提供了對各種優秀框架(如:Struts、Hibernate、MyBatis、Quartz 等)的直接支持 降低 JavaEE API 的使用難度
  • Spring 對 JavaEE 開發中非常難用的一些 API(JDBC、JavaMail、遠程調用等),都提供了封裝,使這些 API 應用難度大大降低。

3. Spring 的版本

Spring 3.X 和 Spring4.X

Spring 3.0.2版本:將市面上常見的、支持整合進來的工具類全部進行了收錄,這個包裏面有很多很多jar包。但是這是Spring堅持“做好事”的最後一個版本,沒有任何回報。

以Spring 4.2.4為例:解壓壓縮包spring-framework-4.2.4.RELEASE-dist.zip

技術分享圖片

  • docs是Spring的文檔,API和開發規範
  • lib下是Spring的jar包和源碼包
  • schema下是Spring當中的約束文件

lib目錄下的包看起來很多,其實是3個一組:

技術分享圖片

二、Spring搭建示例

1. 下載導包

Spring官網:http://spring.io/

下載地址: http://repo.springsource.org/libs-release-local/org/springframework/spring

解壓好的lib下的jar包不會都用,針對需要選擇相應的jar包。

技術分享圖片

2. 創建web項目,引入Spring的開發包

技術分享圖片

在 web/WEB_INF/ 目錄下創建一個lib目錄,把下圖中的4個jar包放進lib目錄下。

技術分享圖片

Spring本身也是支持日誌的,市面上已經有非常成熟的日誌包了,Spring日誌系統使用的是Apache開發出來的日誌包。所以還需要導入Apache的日誌方面的jar包,這部分jar包不在Spring解壓後的lib下,得去Apache官方網站下載。把com.springsource.org.apache.commons.logging-1.1.1.jar和com.springsource.org.apache.log4j-1.2.15.jar復制到lib目錄下。新版本的Spring應該不需要導入com.springsource.org.apache.log4j-1.2.15.jar,導了也不會錯。

技術分享圖片

點擊 File --> Project Structure,進入 Project Structure窗口,點擊 Modules --> 選中項目 --> 切換到 Dependencies 選項卡 --> 點擊下面的“+”,選擇 “JARs or directories...”,選擇創建的lib目錄。

技術分享圖片

技術分享圖片

3. 創建包,編寫一個類文件

技術分享圖片User.java

User.java

4. 書寫Spring的配置文件,註冊對象到Spring容器

對象和框架交流,通過配置文件交流。

Spring的配置文件存放位置任意,放在src目錄下。名字也是任意,但是建議叫applicationContext.xml。

選中src,右鍵選擇New --> XML Configuration File --> Spring Config,輸入名字applicationContext,點擊OK。

技術分享圖片

技術分享圖片

默認生成的文件約束是寫了一些的。在我們這個例子中,上面默認生成的約束就夠用了。

下面開始配置約束,這個user對象要交給Spring容器來管理。

技術分享圖片applicationContext.xml

5. 代碼測試

在 src 下創建一個包:com.wisedu.test,然後創建一個類文件testSpringDemo.java:

package com.wisedu.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext; //這是一個接口,創建容器對象時需要找其實現類
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.wisedu.springDemo.User;

/**
 * Created by jkzhao on 12/7/17.
 */
public class testSpringDemo {

    @Test
    public void test1(){
        //1.創建容器對象(創建Spring的工廠類)
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); //ClassPathXmlApplicationContext(從類路徑下加載xml的Application容器)是org.springframework.context.ApplicationContext的實現類
        //2.向容器"要"User對象(通過工廠解析XML獲取Bean實例)
        User user = (User)ac.getBean("user");
        //3.打印User對象
        System.out.print(user);
    }
}

運行該方法,然後可以發現打印出值了,也就是獲取到了User對象。

技術分享圖片

【註意】:上面在test1方法中,創建容器是使用 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 來創建的,每個項目中只有一個applicationContext對象,不是每個方法中都要創建一下。如何保證只創建一個?

之前學過一個ServletContext域對象,它在一個項目中只有一份,隨著程序的啟動而創建,隨著程序的停止而銷毀。這就用到了Listener。監聽器中有8個監聽器,使用其中一個監聽器:ServletContext域創建和銷毀的Listener。這樣當ServletContext創建時我們可以創建applicationContext對象,當ServletContext銷毀時,我們可以銷毀applicationContext對象。這樣applicationContext就和ServletContext“共生死了”。使用這個監聽器還有一個好處,在監聽器中可以非常方便地獲得事件源,也就意味著我們可以獲得ServletContext對象,這個容器被放進了ServletContext域對象中,說通俗點,就是被放進了application域中。Spring已經把這個監聽器寫好了,我們只需要在web.xml中配置下就可以了。當然還需要導入一個包:spring-web-4.2.4.RELEASE.jar

<listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

前面在講到Spring容器時說道,Spring的配置文件位置任意,Spring配置文件名字任意,所以這意味著還需要在web.xml中指明該配置文件的位置及名稱。

<!-- 可以讓spring容器隨著項目的啟動而創建,隨項目的關閉而銷毀-->
<listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--指定加載Spring配置文件的位置-->
<context-param>
      <param-name>contextConfigLocation</param-name> <!--這個key不能改,背下來-->
      <param-value>
            classpath*:/applicationContext.xml
      </param-value>
</context-param>

接著寫java代碼從application域中獲取容器。但是application域中存放東西是鍵值對存在的,我們得知道鍵才能取。Spring考慮到這種情況,準備了一個工具方法,把鍵封裝在工具方法中了。

//1.這裏以Struts2為例獲取ServletContext對象
ServletContext sc = ServletActionContext.getServletContext();
//2.從sc中獲得ac容器
WebApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(sc);
//3.從容器中獲得需要的對象
... 

三、Spring概念

1. IOC思想和DI技術

(1)IOC (Inverse Of Control):控制反轉,將我們創建對象的方式反轉了。

以前對象的創建是由開發人員自己維護,包括依賴關系也是自己註入。使用了Spring之後,對象的創建以及依賴關系可以由Spring完成創建以及註入。

(2)DI(Dependency Injection):依賴註入。將必須的屬性註入到對象當中,是實現IOC思想的必要條件。

需要有 IOC 的環境,Spring 創建這個類的過程中,Spring 將類的依賴的屬性設置進去。

註入方式:

  • set方法註入
  • 構造方法註入
  • 字段註入:不建議。

註入類型:

  • 值類型註入:8大基本數據類型。比如上面示例中的User對象,它裏面有name和age兩個屬性,現在我們希望User對象創建出來後,name="Tom",age=18。這個"Tom"和18可以在配置文件中配置,這樣Spring會把我們配置的值自動交給屬性。
  • 引用類型註入:將依賴的對象註入

所以實現IOC思想需要DI支持,DI對IOC提供了技術上的支撐。

2. Spring中的工廠(容器)

(1)ApplicationContext

ApplicationContext接口有兩個實現類:

  • ClassPathXmlApplicationContext :加載類路徑下 Spring 的配置文件
  • FileSystemXmlApplicationContext :從絕對路徑上加載本地磁盤下 Spring 的配置文件,基本用不著。

技術分享圖片

(2)BeanFactory(過時)

BeanFactory是個接口,是Spring框架在初創時創建的第一個接口。像這種初創的接口,功能一般是很少的,針對原始接口的實現類功能較為單一。下面是幅繼承關系圖。

技術分享圖片

(3)BeanFactory 和 ApplicationContext 的區別

BeanFactory接口的實現類的容器特點是:每次在獲得對象時才會創建對象。比如上面示例中的代碼,

User user = (User)ac.getBean("user"); //只有在獲取對象時才會創建對象

而ApplicationContext接口實現類的容器特點是:在加載applicationContext.xml(容器啟動)時候就會創建容器中配置的所有對象。除此以外,提供更多功能。

總結:在web開發中,使用applicationContext,在硬件資源匱乏的環境使用BeanFactory。

四、Spring配置詳解

1. Bean元素的配置

Bean元素:凡是交給Spring容器管理的對象都是由Bean來描述。

  • name屬性:給被管理的對象起個名字。獲得對象時根據該名稱獲得對象
  • class屬性:被管理對象的完整類名
  • id屬性:早年使用的,功能與name屬性一模一樣,id的規矩:名稱不能重復,不能使用特殊字符。所以加了name屬性,可以使用特殊字符,名稱也可以重復,但是不推薦名稱重復。

結論:盡量使用name屬性。

2. Spring生成Bean的三種方式(三種對象創建方式)

對象的創建必須經過類的構造函數。

(1)空參構造創建 --最重要

在上面示例中的User對象中加一個無參構造函數

重新創建一個包,把applicationContext.xml復制進該包中,把測試類testSpringDemo.java復制進該包中,並修改該文件中applicationContext.xml的位置。

技術分享圖片

具體代碼如下:

技術分享圖片User.java 技術分享圖片applicationContext.xml 技術分享圖片testSpringDemo.java

運行結果:

技術分享圖片

(2)靜態工廠方式 --了解

寫一個類,在類中建一個方法,該方法中把user創建出來。調用該方法創建user,然後交給Spring容器來管理,這樣就不是Spring來創建對象了,我們希望Spring調用這個方法創建對象

技術分享圖片UserFactory.java 技術分享圖片applicationContext.xml 技術分享圖片testSpringDemo.java

技術分享圖片

(3)實例工廠方式 --了解

public User createUser2(){
        System.out.println("實例工廠創建User");

        return new User();
}

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 創建方式1:空參構造創建 -->
    <bean name="user" class="com.wisedu.springDemo.User"></bean>

    <!-- 創建方式2:靜態工廠創建
            調用UserFactory的createUser方法來創建名為User2的對象放入容器
    -->
    <bean name="user2" class="com.wisedu.createObject.UserFactory" factory-method="createUser"></bean>

    <!-- 創建方式3:實例工廠創建
        首先將UserFactory作為普通的bean配置到Spring中,然後再去調用UserFactory對象的createUser2方法
-->
    <bean name="user3" factory-bean="userFactory" factory-method="createUser2"></bean>
    <bean name="userFactory" class="com.wisedu.createObject.UserFactory"></bean>
</beans>

測試方法:

    @Test
    //創建方式3:實例工廠創建對象
    public void test3(){
        //1.創建容器對象(創建Spring的工廠類)
        ApplicationContext ac = new ClassPathXmlApplicationContext("com/wisedu/createObject/applicationContext.xml"); //ClassPathXmlApplicationContext(從類路徑下加載xml的Application容器)是org.springframework.context.ApplicationContext的實現類
        //2.向容器"要"User對象(通過工廠解析XML獲取Bean實例)
        User user = (User)ac.getBean("user3");
        //3.打印User對象
        System.out.print(user);
    }

技術分享圖片

3. bean元素的scope屬性

scope屬性是在bean元素上加的。

  • singleton :默認值,單例對象。被標識為單例的對象在Spring容器中只會存在一份實例。
  • prototype :多例的。被標識為多例的對象每次在獲得時才會創建,並且每次創建都是新的對象。單例對象是在容器啟動時就創建了。
  • request :WEB 項目中,Spring 創建一個 Bean 的對象,將對象存入到 request 域中。對象與request生命周期一致。 --基本不用
  • session :WEB 項目中,Spring 創建一個 Bean 的對象,將對象存入到 session 域中。對象與session生命周期一致。 --基本不用
  • globalSession :WEB 項目中,應用在 Porlet 環境。如果沒有 Porlet 環境那麽 globalSession 相當於 session。 --基本不用

在未來的開發中,絕大多數scope的取值都是使用默認值,但是Spring與Struts2整合時,action對象要交給Spring來管理,action這個bean得配置為prototype。因為Struts2從架構上來說,每次請求都會創建一個新的action。

4. bean元素的生命周期屬性 --了解

通過配置<bean>標簽上的 init-method 作為 Bean 的初始化的時候執行的方法,Spring會在對象創建之後立即調用。配置 destroy-method 作為 Bean 的銷毀的時候執行的方法。

【註意】:銷毀方法想要執行,需要是單例創建的 Bean,而且在工廠關閉的時候,Bean 才會被銷毀.

5. Spring的分模塊配置文件

實際開發中,可能會把Sprign的配置寫到多個文件中,這時可以在Spring主配置文件中引入其他Spring配置文件。

<!-- 導入其他Spring配置文件-->
<import resource="applicationContext.xml" />

6. Spring中的Bean的屬性註入

(1)set方法註入屬性 --最重要

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--set方式註入:值類型和引用類型-->
    <bean name="user" class="com.wisedu.springDemo.User">
        <!--為User對象中名為name的屬性註入tom作為值-->
        <property name="name" value="tom"></property>
        <property name="age" value="18"></property>
        <!--為car屬性註入下方配置的car對象-->
        <property name="car" ref="car"></property>
    </bean>

    <!--必須將car對象配置到容器中-->
    <bean name="car" class="com.wisedu.springDemo.Car">
        <property name="name" value="蘭博基尼"></property>
        <property name="color" value="黃色"></property>
    </bean>

</beans>
技術分享圖片User.java 技術分享圖片Car.java

測試方法:

    @Test
    public void test1(){
        //1.創建容器對象(創建Spring的工廠類)
        ApplicationContext ac = new ClassPathXmlApplicationContext("com/wisedu/injection/applicationContext.xml"); //ClassPathXmlApplicationContext(從類路徑下加載xml的Application容器)是org.springframework.context.ApplicationContext的實現類
        //2.向容器"要"User對象(通過工廠解析XML獲取Bean實例)
        User user = (User)ac.getBean("user");
        //3.打印User對象
        System.out.println(user);
    }

運行結果:

技術分享圖片

(2)構造函數註入屬性 --重要

前提:類中得有帶有參數的構造函數。

在上面的User.java中添加擁有兩個參數的構造方法:

public User(String name, Car car) {
        System.out.println("User(String name, Car car)");
        this.name = name;
        this.car = car;
}

在applicationContext.xml文件中添加配置:

    <!-- ============================================== -->
    <!-- 構造函數註入 -->
    <bean name="user2" class="com.wisedu.springDemo.User">
        <constructor-arg name="name" value="jerry"></constructor-arg>
        <constructor-arg name="car" ref="car"></constructor-arg>
    </bean>

測試方法:

    @Test
    public void test2(){
        //1.創建容器對象(創建Spring的工廠類)
        ApplicationContext ac = new ClassPathXmlApplicationContext("com/wisedu/injection/applicationContext.xml"); //ClassPathXmlApplicationContext(從類路徑下加載xml的Application容器)是org.springframework.context.ApplicationContext的實現類
        //2.向容器"要"User對象(通過工廠解析XML獲取Bean實例)
        User user = (User)ac.getBean("user2");
        //3.打印User對象
        System.out.println(user);

    }

運行結果:

技術分享圖片

但是假設我們User類中有多個構造方法,裏面參數位置不一樣,代表實際業務中不同的邏輯,比如:

public User(String name, Car car) {
        System.out.println("User(String name, Car car)");
        this.name = name;
        this.car = car;
    }

    public User(Car car, String name) {
        System.out.println("User(Car car, String name)");
        this.name = name;
        this.car = car;
    }

我們如何在配置文件中指定走哪個構造方法呢?需要index屬性,index=0表示該屬性是構造方法中的第一個參數,index=1表示該屬性是構造方法中的第二個參數。

    <!-- ============================================== -->
    <!-- 構造函數註入 -->
    <bean name="user2" class="com.wisedu.springDemo.User">
        <constructor-arg name="name" value="jerry" index="0"></constructor-arg>
        <constructor-arg name="car" ref="car" index="1"></constructor-arg>
    </bean>

技術分享圖片

還有一種情況,構造方法是這樣的,代表另一種業務。

public User(String name, Car car) { //業務1
        System.out.println("User(String name, Car car)");
        this.name = name;
        this.car = car;
    }

    public User(Car car, String name) { //業務2
        System.out.println("User(Car car, String name)");
        this.name = name;
        this.car = car;
    }

    public User(Integer name, Car car) { //業務3
        System.out.println("User(Integer name, Car car)");
        this.name = name + "";
        this.car = car;
    }

配置:

    <!-- ============================================== -->
    <!-- 構造函數註入 -->
    <bean name="user2" class="com.wisedu.springDemo.User">
        <!--name屬性:構造函數的參數名-->
        <!--index屬性:構造函數的參數索引-->
        <!--type屬性:構造函數的參數的類型-->
        <constructor-arg name="name" value="999" index="0" type="java.lang.Integer"></constructor-arg>
        <constructor-arg name="car" ref="car" index="1"></constructor-arg>
    </bean>

技術分享圖片

(3)p名稱空間註入屬性 --了解

需要引入p名稱空間。

    <!-- ============================================== -->
    <!-- p名稱空間註入,本質走的還是set方法,只不過這種寫法是Spring新發明了,簡化了set的寫法。 -->
    <!--1.需要p名稱空間:xmlns:p="http://www.springframework.org/schema/p"
        2.使用p:屬性註入
            值類型:p:屬性名="值"
            引用類型:p:屬性名-ref="bean名稱"
    -->
    <bean name="user3" class="com.wisedu.springDemo.User" p:name="jack" p:age="20" p:car-ref="car"></bean>

  

(4)spel註入屬性 --了解

    <!-- ============================================== -->
    <!-- spel註入:Spring Expression Language,Spring表達式語言,類似el、jstl表達式-->
    <bean name="user4" class="com.wisedu.springDemo.User">
        <property name="name" value="#{user.name}"></property> <!--找name="user"的對象,找它的屬性name-->
        <property name="age" value="#{user3.age}"></property>
        <property name="car" ref="car"></property> <!--引用類型不允許使用spel表達式-->
    </bean>

(5)復雜類型的註入

前面講的註入類型要麽就是值,要麽就是對象。如果遇到數組、Map、List或properties,該如何註入?直接使用set方式註入這幾種復雜類型。

技術分享圖片CollectionBean.java 技術分享圖片復雜類型註入

測試方法:

    @Test
    public void test5(){
        //1.創建容器對象(創建Spring的工廠類)
        ApplicationContext ac = new ClassPathXmlApplicationContext("com/wisedu/injection/applicationContext.xml"); //ClassPathXmlApplicationContext(從類路徑下加載xml的Application容器)是org.springframework.context.ApplicationContext的實現類
        //2.向容器"要"User對象(通過工廠解析XML獲取Bean實例)
        CollectionBean cb = (CollectionBean)ac.getBean("cb");
        //3.打印User對象
        System.out.println(cb);

    }

五、使用註解配置Spring(代替xml配置)

Hibernate、Struts2、Spring都支持註解方式配置。註解是JDK1.5開始引入的,這三大框架都是在JDK1.5以前出來的。但是在開發中很少使用註解來配置Hibernate和Struts2。

1. 註解示例

新建一個包,com.wisedu.annotation。

(1)Spring 4.2.4使用註解還需要導入一個包

spring-aop-4.2.4.RELEASE.jar 老版本不需要。

(2)為主配置文件引入新的命名空間(約束)

在默認生成的applicationContext.xml文件中添加配置

xmlns:context="http://www.springframework.org/schema/context"

在 xsi:schemaLocation= 後面添加如下配置:

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd

(3)在主配置文件中開啟使用註解代理配置文件(打開使用註解的開發)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--component可以理解為對象,我們把對象放進容器中,對Spring來說就是把組件放進來了-->
    <!--base-package: 掃描你給的這個包下所有的類,看上面有沒有註解。掃描到註解,會啟動註解配置。
                      如果這個包下面還有子包的話,還會掃描子包下的類
    -->
    <context:component-scan base-package="com.wisedu"></context:component-scan>
</beans>

(4)在類中使用註解完成配置

技術分享圖片User.java

其中,@Component()是Spring在註冊Bean的一個早期註解,後來又出現了這麽幾個註解:@Service()、@Controller、@Repository()

一開始只有@Component(),但是後來使用者向Spring反饋,在註冊項目中所有對象的時候,都有這同一個註解,這樣很難區分這個對象屬於哪一層,所以又增加3個註解。這3個註解和@Component()沒有任何區別,但是這3個註解通過看名字,就知道註冊的對象屬於哪一層。

  • @Service():註冊service層對象
  • @Controller:註冊web層對象
  • @Repository():註冊Dao層對象

(5)測試

技術分享圖片test.java

2. 註解形式下對象的作用範圍

@Scope(scopeName = "prototype") //默認是單例的

技術分享圖片User.java 技術分享圖片測試方法

3. 屬性的註入

(1)值賦值

在成員變量上面加註釋@Value(),或者把這個註釋放到這個成員變量的set方法上。

技術分享圖片User.java

這兩種的區別:

加在成員變量上,Spring在給這個對象賦值的時候,通過反射的Field賦值。而放在成員的set方法上,走的set方法賦值的(推薦使用)。

雖然結果是一樣的,但是放在成員變量上破壞了對象的封裝性。本來這個屬性私有,就是為了封裝,提供get和set方法操作,加在成員變量上就是Spring直接去操作對象了。

所以在set方法上加是推薦上,但是在成員變量上加很清晰,方便,在set方法上加很別扭,這就很矛盾。實際使用上兩種都可以。

另外,上面的示例中:@Value(value="18")和@Value("18")是一樣的,這是一個結論(直接記住):如果註解中的屬性如果只有一個需要賦值,並且這個屬性名是value的話,寫的時候可以忽略屬性的鍵,也就是忽略"value"。包括前面寫的@Component("user"),沒寫鍵的,都是給value賦值的。

(2)引用類型賦值

首先你必須把賦值的對象給註冊到容器中,比如上面示例中的car。

多種方式實現對象賦值:

第一種:

User.java代碼片段:

@Component("user")
@Scope(scopeName = "prototype") //默認是單例的
public class User {
    @Value("tom")
    private String name;
    private Integer age;
    @Autowired //自動裝配。根據類型來檢測掃描容器當中符合這個屬性類型的對象,如果檢測到了,找到這個對象,賦值給這個屬性
    @Qualifier("car2")
    private Car car;
  ...

其中,Car.java代碼片段:

@Component("car")
public class Car {
    @Value("蘭博基尼")
    private String name;
    @Value("屎黃色")
    private String color;
    ...

運行結果:

技術分享圖片

這種註入引用類型有個缺陷,假如我把這個Car註冊到好幾遍這個容器當中,假如在容器中有3輛車。比如這個在applicationContext.xml中在配置輛車。

    <bean name="car2" class="com.wisedu.annotation.Car">
        <property name="name" value="特斯拉"></property>
        <property name="color" value="藍色"></property>
    </bean>

這樣Spring中就有兩輛車了。這樣我們無法控制具體將哪輛車註入Car屬性。這個時候我們可以給 @Autowired 加個輔助註解,

    @Autowired 
    @Qualifier("car2")
    private Car car;

再次運行:

技術分享圖片

第二種:當引用對象有多個的時候,需要把該對象註入給某屬性時,不建議使用上面兩個註解,有個註解不是自動裝配,直接“指名道姓”,叫@Resource(name = "car2")

    //@Autowired //自動裝配。根據類型來檢測掃描容器當中符合這個屬性類型的對象,如果檢測到了,找到這個對象,賦值給這個屬性
    //@Qualifier("car2")
    @Resource(name = "car2") //手動註入,指定註入哪個名稱的對象
    private Car car;

4. 初始化和銷毀方法

User.java代碼片段:

    @PostConstruct //在對象被創建後調用,類似於之前學習的init-method
    public void init(){
        System.out.println("初始化方法");
    }
    @PreDestroy //在對象銷毀之前調用,類似於之前學習的destory-method
    public void destory(){
        System.out.println("銷毀方法");
    }

【註意】:如果想執行銷毀方法,必須將User對象改為單例的。

Spring的Bean管理方式的比較:

技術分享圖片

XML和註解:

  • XML:結構清晰
  • 註解:開發方便(屬性註入)


實際開發中還有一種 XML 和註解整合開發:

  • Bean 有 XML 配置,但是使用的屬性使用註解註入

Spring介紹及配置(XML文件配置和註解配置)