不會使用Spring的配置檔案,趕緊把這個甩給他

語言: CN / TW / HK
摘要:文章從Spring程式的快速使用、Bean標籤的使用和其屬性的具體使用,每個屬性都用程式碼來解釋,執行結果和案例也寫的都很明白。

本文分享自華為雲社群《怎樣使用Spring的配置檔案?帶大家一起玩轉Spring配置檔案》,作者:我是一棵捲心菜 。

一、Spring程式快速入門

步驟一:匯入 Spring 開發的基本包座標

建立一個maven工程,匯入Spring需要的依賴,為了方便測試,我還匯入了一個Junit測試包

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.14</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

步驟二:編寫 Dao 介面和實現類

接下里,需要編寫一個Dao介面和其實現類,用來搭建測試的環境,話多不說,直接上程式碼

public interface UserDao {
    void save();
}
public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("儲存成功~~");
    }
}

步驟三:建立 Spring 核心配置檔案

介面和類寫完後,就開始進入正題,在類路徑下(resources)建立Spring的核心配置檔案,我取名為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">
</beans>

步驟四:在 Spring 配置檔案中配置 UserDaoImpl類

建立好xml配置檔案後,我要想呼叫save()方法,就需要建立UserDaoImpl類的物件,這裡採用容器的方式。

    <bean id="userdao" class="com.sht.dao.impl.UserDaoImpl"></bean>

這裡的id是自定義的,最好是類名的首字母小寫,方便於記憶。class屬性值是要建立類物件的所在包路徑,我的這個UserDaoImpl類所在的包路徑就是com.sht.dao.impl.UserDaoImpl,這一點都不能寫錯哦!

步驟五:使用 Spring 的 API 獲得 Bean 例項

接下來測試一下:

public class UserDaoDemo {
    public static void main(String[] args) {
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userdao = (UserDao) applicationContext.getBean("userdao");
        userdao.save();
    }
}

通過new ClassPathXmlApplicationContext("applicationContext.xml")獲取到容器——applicationContext,然後通過id對應的屬性值獲取到UserDaoImpl類的物件,這樣我們就不需要用new的方式來建立物件了!

以上java程式碼還可以寫成另一種方式:

public class UserDaoDemo {
    public static void main(String[] args) {
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDaoImpl userDao = applicationContext.getBean(UserDaoImpl.class);
        userDao.save();
    }
}

其中,當引數的資料型別是字串時,表示根據Bean的id從容器中獲得Bean例項,返回是Object,需要強轉。

當引數的資料型別是Class型別時,表示根據型別從容器中匹配Bean例項,特別注意的是:當容器中相同型別的Bean有多個時,則此方法會報錯。

執行結果:

結果正確,到了這裡,spring的配置檔案你已經有了基本的瞭解,接下來讓我們看看spring配置檔案中其它的細節使用吧!

二、Spring配置檔案使用

1、Bean標籤基本配置

基本介紹

用於配置物件交由Spring 來建立

預設情況下它呼叫的是類中的無參建構函式,如果沒有無參建構函式則不能建立成功,對於有參構造器,後面會慢慢講到

基本屬性

id:Bean例項在Spring容器中的唯一標識
class:Bean的全限定名稱

這兩個基本屬性在快速入門中已經使用過了,就不最多介紹了

Bean標籤範圍配置(Scope)

修改xml配置檔案,在原來的bean中加入scope="singleton",這就意味著,我們不管建立多少個物件,都是同一個

<bean id="userdao" class="com.sht.dao.impl.UserDaoImpl" scope="singleton"></bean>

寫一個測試程式碼

    public void test1(){
        ApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userdao1 = (UserDao) context.getBean("userdao");
        System.out.println(userdao1);
        UserDao userdao2 = (UserDao) context.getBean("userdao");
        System.out.println(userdao2);
        System.out.println("是否為同一個物件例項:" + (userdao1 == userdao2));
    }

執行結果:

繼續修改xml配置檔案,把scope="singleton"改為scope="prototype",即表明,我們用其建立物件時,不是同一個物件例項

上面的測試程式碼不變,執行結果:

Bean標籤例項化時機

小夥伴們可能就有疑問了,上面這兩種方式是什麼時候建立物件例項的呢?不要急,咱們慢慢道來。

為了方便效果的展現,我在UserDaoImpl類的無參構造器中加入一句程式碼,用來區別建立例項的時機

  public UserDaoImpl(){
        System.out.println("UserDaoImpl開始建立");
    }

scope為singleton時

執行debug,點選F8

我們可以發現,從載入配置檔案的時候就開始建立了物件例項

scope為prototype時

執行debug,按下F8,發現控制檯並沒有列印“UserDaoImpl開始建立”,說明配置檔案並沒有載入物件例項

再次按F8下一步

我們可以發現控制檯終於列印了“UserDaoImpl開始建立”

總結

當scope的取值為singleton時,當應用載入,建立容器時,物件就被建立了;當scope的取值為prototype時,當使用物件時,才建立新的物件例項。

Bean生命週期配置

在UserDaoImpl類中新增兩個方法

  public void init(){
        System.out.println("初始化方法");
    }
  public void destory(){
        System.out.println("銷燬方法");
    }

修改xml配置檔案,init-method:指定類中的初始化方法名稱,destroy-method:指定類中銷燬方法名稱

<bean id="userdao" class="com.sht.dao.impl.UserDaoImpl"
          scope="singleton"
          init-method="init"
          destroy-method="destory">
</bean>

編寫測試程式碼

public void test3(){
        ApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userdao1 = (UserDao) context.getBean("userdao");
        System.out.println(userdao1);
        UserDao userdao2 = (UserDao) context.getBean("userdao");
        System.out.println(userdao2);
        System.out.println("是否為同一個物件例項:" + (userdao1 == userdao2));
        //這裡用來關閉容器
        ((ClassPathXmlApplicationContext) context).close();
    }

執行結果:

從這個例子,相信大家可以自己推測出建立物件、初始化、方法呼叫以及銷燬的先後順序了

Bean例項化三種方式

方式一:無參構造方法例項化(重點)

其實我們前面一直使用的就是這一種方法,但是需要注意的是,這種方法會根據預設無參構造方法來建立類物件,如果bean中沒有預設無參建構函式,將會建立失敗

方式二:工廠靜態方法例項化(瞭解)

建立一個靜態工廠類,直接返回UserDaoImpl類的物件例項

public class StaticFactory {
    public static UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

編寫xml配置檔案的bean,這裡的class屬性值是靜態工廠類對應的包的路徑,factory-method對應的屬性值是類中的方法名

<bean id="userdao" class="com.sht.factory.StaticFactory" factory-method="getUserDao"></bean>

編寫程式碼測試

public class UserDaoDemo {
    public static void main(String[] args) {
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userdao = (UserDao) applicationContext.getBean("userdao");
        userdao.save();
    }
}

最終的執行結果還會是:“儲存成功~~”

方式三:工廠例項方法例項化(瞭解)

建立一個工廠類,同樣返回UserDaoImpl類的物件例項

public class DynamicFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

編寫xml配置檔案的bean,這裡的class屬性值是工廠類對應的包的路徑,第一個bean可以得到工廠類的物件,再寫一個bean,用來獲取UserDaoImpl類的物件例項。factory-bean屬性值代表從哪個工廠裡面拿,factory-method對應的屬性值是類中的方法名

<bean id="factory" class="com.sht.factory.DynamicFactory"></bean>
<bean id="userdao" factory-bean="factory" factory-method="getUserDao"></bean>

最終的執行結果也是:“儲存成功~~”

總結

2、Bean的依賴注入

基本介紹

依賴注入(Dependency Injection):它是 Spring 框架核心 IOC 的具體實現。

在編寫程式時,通過控制反轉,把物件的建立交給了 Spring,但是程式碼中不可能出現沒有依賴的情況。IOC 解耦只是降低他們的依賴關係,但不會消除。例如:業務層仍會呼叫持久層的方法。

那這種業務層和持久層的依賴關係,在使用 Spring 之後,就讓 Spring 來維護了。
簡單的說,就是坐等框架把持久層物件傳入業務層,而不用我們自己去獲取。

Bean的依賴注入方式

方式一:有參構造方法

前面講的都是無參構造方法,現在講講有參構造方法。我們先建立一個UserService介面和其實現類UserServiceImpl

public interface UserService {
    void save();
}
public class UserServiceImpl implements UserService {
    private UserDao userdao;
    public UserServiceImpl(UserDao userdao) {
        this.userdao = userdao;
    }
    @Override
    public void save() {
        userdao.save();
    }
}

編寫xml配置檔案的bean,class屬性值分別對應類下的包路徑。<constructor-arg name="userdao" ref="userdao"></constructor-arg>中name屬性值是相應set方法名的去掉set後的首字母小寫,ref是引入引入資料型別,即表示著物件屬性的注入

  <bean id="userdao" class="com.sht.dao.impl.UserDaoImpl"></bean>
  <bean id="userService"  class="com.sht.service.impl.UserServiceImpl">
        <constructor-arg name="userdao" ref="userdao"></constructor-arg>
  </bean>

方式二:set方法

介面不變,改變一下UserServiceImpl 類,需要注意的是,setUserdao()的許可權是public,不能寫成private哦

public class UserServiceImpl implements UserService {
    private UserDao userdao;
    //許可權是public
    public void setUserdao(UserDao userdao){
        this.userdao = userdao;
    }
    @Override
    public void save() {
        userdao.save();
    }
}

編寫xml配置檔案的bean,class屬性我就不再說明了。重點講解的是<property name="userdao" ref="userdao"></property>;name屬性值是相應set方法名的去掉set後的首字母小寫,ref是引入引入資料型別,即表示著物件屬性的注入;這裡把UserDaoImpl類的物件注入到UserServiceImpl類中,就可以呼叫其save()方法了

  <bean id="userdao" class="com.sht.dao.impl.UserDaoImpl"></bean>
  <bean id="userService"  class="com.sht.service.impl.UserServiceImpl">
        <property name="userdao" ref="userdao"></property>
  </bean>
測試程式碼:
public void test5(){
        ApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userService");
        userService.save();
    }

執行結果:

此外,set方法中有一個特殊的方法:P名稱空間注入。其本質也是set方法注入,但比起上述的set方法注入更加方便,主要體現在配置檔案中,如下:

引入xmlns:p="http://www.springframework.org/schema/p"名稱空間,其次p:userdao-ref屬性值是跟ref對應的屬性值的含義是一樣的,這種方法可以作為了解

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 
    <bean id="userdao" class="com.sht.dao.impl.UserDaoImpl"></bean>  
    <bean id="userService" class="com.sht.service.impl.UserServiceImpl" p:userdao-ref="userdao"></bean>
</beans>

3、Bean的依賴注入資料型別

普通資料型別的注入

我用set方法的方式,講解bean的依賴注入。繼續在UserDaoImpl類中新增兩個基本資料型別和它們的set方法

    private String name;
    private Integer age;
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public void show() {
        System.out.println("名字是" + name + "的年齡是" + age);
    }

修改xml配置檔案的bean,name的屬性值代表著set方法的名,value的屬性值表示你想要填入的屬性值

<bean id="userDao" class="com.sht.dao.impl.UserDaoImpl">
        <property name="name" value="捲心菜"></property>
        <property name="age" value="20"></property>
</bean>

寫一個測試類:

   public void test7(){
        ApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDaoImpl contextBean = context.getBean(UserDaoImpl.class);
        contextBean.show();
    }

執行結果:

集合資料型別的注入

List<String>型別的注入

繼續在UserDaoImpl類中改動程式碼:
    private List<String> stringList;
    public void setStringList(List<String> stringList) {
        this.stringList = stringList;
    }
    public void showStringList() {
        System.out.println(stringList);
    }

修改xml配置檔案,注入基本資料型別就是兩個關鍵字<list>和<value>

  <bean id="userDao" class="com.sht.dao.impl.UserDaoImpl">
       <property name="stringList">
          <list>
              <value>111</value>
              <value>222</value>
              <value>333</value>
          </list>
       </property>
  </bean>

執行結果:

List<User>型別的注入

先建立一個User類,有對應的get和set方法,還有toString方法,方便測試使用

public class User {
    private Integer id;
    private String username;
    private String password;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

修改xml配置檔案的bean,可以看出,與之前不同的是,<list>中用的是<ref>標籤,這個標籤表示的是注入引用資料型別

 <bean id="user01" class="com.sht.domain.User">
        <property name="id" value="1"></property>
        <property name="username" value="捲心菜"></property>
        <property name="password" value="123456"></property>
 </bean>
 
    <bean id="user02" class="com.sht.domain.User"></bean>
 
    <bean id="userDao" class="com.sht.dao.impl.UserDaoImpl">
       <property name="userList">
           <list>
               <ref bean="user01"></ref>
               <ref bean="user02"></ref>
           </list>
       </property>
    </bean>

執行結果:

Map<String,User> 型別的注入

繼續在UserDaoImpl類中改動程式碼:

    private Map<String, User> stringUserMap;
    public void setStringUserMap(Map<String, User> stringUserMap) {
        this.stringUserMap = stringUserMap;
    }
    public void showStringUserMap() {
        System.out.println(stringUserMap);
    }

修改xml配置檔案,與之前不同的是,當使用的是map時,標籤用的是<map>和標籤<entry>,使用方法跟list標籤差不多

    <bean id="user01" class="com.sht.domain.User">
        <property name="id" value="1"></property>
        <property name="username" value="捲心菜"></property>
        <property name="password" value="123456"></property>
    </bean>

    <bean id="userDao" class="com.sht.dao.impl.UserDaoImpl">
        <property name="stringUserMap">
         <map>
             <entry key="key1" value-ref="user01"></entry>
         </map>
        </property>
    </bean>

執行結果:

需要注意的是,我們在選擇key屬性時,會有一個如圖所示的key-ref的提示,這代表著我們要用的key是一個引入資料型別,因為我用的key是String,所以選擇key

當使用value-ref時,也會出現value的值,其用法跟上面一樣

Properties型別的注入

繼續在UserDaoImpl類中改動程式碼:

    private Properties properties;
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
    public void showProperties(){
        System.out.println(properties);
    }

修改xml配置檔案,與之前的不同之處就是標籤使用的是<props>和標籤<prop>,使用的方法也是跟上面的方法類似

 <bean id="userDao" class="com.sht.dao.impl.UserDaoImpl">
       <property name="properties">
           <props>
               <prop key="key01">value1</prop>
               <prop key="key02">value2</prop>
           </props>
       </property>
 </bean>

執行結果:

4、引入其他配置檔案(分模組開發)

建立一個新的配置檔案applicationContext1.xml,實際開發中,Spring的配置內容非常多,這就導致Spring配置很繁雜且體積很大,所以,可以將部分配置拆解到其他配置檔案中,而在Spring主配置檔案通過import標籤進行載入

把applicationContext1.xml配置檔案中的配置內容引入到applicationContext.xml的實現方式:

<import resource="applicationContext1.xml"></import>

總結

以上就是Spring配置檔案的相關知識點,帶大家來看看Spring的重點配置:

 

點選關注,第一時間瞭解華為雲新鮮技術~