天天看點

【Spring】— Spring中Bean的裝配方式

作者:馬士兵老師

Bean的裝配方式

Bean的裝配可以了解為依賴關系注入,Bean的裝配方式即Bean依賴注入的方式。Spring容器支援多種形式的Bean裝配方式,如基于XML的裝配、基于Annotation(注解)的裝配和自動裝配等。

1.基于XML的裝配

Spring提供了兩種基于XML的裝配方式:設值注入(Setter Injection)和構造注入(Constructor Injection)。下面講解如何在XML配置檔案中使用這兩種注入方式來實作基于XML的裝配。在Spring執行個體化Bean的過程中,Spring首先會調用Bean的預設構造方法來執行個體化Bean對象,然後通過反射的方式調用setter()方法來注入屬性值。是以,設值注入要求一個Bean必須滿足以下兩點要求: 

  • Bean類必須提供一個預設的無參構造方法。 
  • Bean類必須為需要注入的屬性提供對應的setter()方法。

使用設值注入時,在Spring配置檔案中需要使用bean元素的子元素property來為每個屬性注入值;

使用構造注入時,在配置檔案中需要使用bean元素的子元素constructor-arg來定義構造方法的參數,可以使用其value屬性(或子元素)來設定該參數的值。

【示例2-2】下面通過一個案例來示範基于XML方式的Bean的裝配。

(1)在項目chapter02的src目錄下建立一個com.ssm.assemble包,在該包中建立User類,并在類中定義userName、password和list集合3個屬性及對應的setter()方法。

java複制代碼User.java

package com.ssm.assemble;

import java.util.List;

/**
 * 功能描述
 *
 * @author: 衍生星球
 * @date: 2023年04月14日 8:24
 */

public class User {
    private String userName;
    private String password;
    private List<String> list;

    /**
     * 1.使用構造注入
     * 1.1提供帶所有參數的構造方法
     */
    public User(String userName,String password,List<String> list) {
        super();
        this.userName = userName;
        this.password = password1;
        this.list = list;
    }
    @Override
    public String toString () {
        return "User[userName = " +userName+ ", password1 = "+password1+", list = "+list+"]";
    }
    /**
     * 2.使用設值注入
     * 2.1提供預設空參構造方法
     * 2.2為所有屬性提供setter()方法
     */
    public User() {
        super();
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
}
           

由于要使用構造注入,是以需要編寫有參和無參的構造方法。

(2)在Spring的配置檔案application.xml中,增加通過構造注入和設值注入的方法裝配User執行個體的兩個Bean。

java複制代碼 	<bean id="user1" class="com.ssm.assemble.User">
        <constructor-arg index="0" value="zhangsan" />
        <constructor-arg index="1" value="111111" />
        <constructor-arg index="2">
            <list>
                <value>"constructorValue1"</value>
                <value>"constructorValue2"</value>
            </list>
        </constructor-arg>
    </bean>
    <bean  id="user2" class="com.ssm.assemble.User">
        <property name="userName" value="lisi"></property>
        <property name="password" value="222222"></property>
        <property name="list">
            <list>
                <value>listValue1</value>
                <value>listValue2</value>
            </list>
        </property>
    </bean>
           

在上述代碼中,constructor-arg元素用于定義構造方法的參數,其屬性index表示其索引(從0開始),value屬性用于設定注入的值,其子元素list為User類中對應的list集合屬性注入值。

然後又使用設值注入方法裝配User類的執行個體,其中property元素用于調用Bean執行個體中的setter()方法完成屬性指派,進而完成依賴注入,而其子元素list同樣為User類中對應的list集合屬性注入值。

(3)在com.ssm.assemble包中建立測試類XmlAssembleTest,在類中分别擷取并輸出配置檔案中的user1和user2執行個體。

java複制代碼XmlAssembleTest.java

package com.ssm.assemble;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author: 衍生星球
 * @date: 2023年04月14日 9:08
 */

public class XmlAssembleTest {
    public static void main(String[] args) {
        //1.初始化Spring容器,加載配置檔案
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.輸出獲得的執行個體
        System.out.println(applicationContext.getBean("user1"));
        System.out.println(applicationContext.getBean("user2"));
    }
}
           

執行程式後,控制台輸出結果如下。可以看出,已經成功地使用基于XML裝配的構造注入和設值注入兩種方式裝配了User執行個體。

【Spring】— Spring中Bean的裝配方式

2.基于Annotation的裝配

在Spring中,盡管使用XML配置檔案可以實作Bean的裝配工作,但如果應用中有很多Bean,就會導緻XML配置檔案過于臃腫,給以後的維護和更新工作帶來一定的困難。為此,Spring提供了對Annotation(注解)技術的全面支援。Spring中定義了一系列的注解,常用的注解如表所示。

【Spring】— Spring中Bean的裝配方式

注意:雖然@Repository、@Service和@Controller的功能與@Component注解的功能相同,但為了使标注類本身用途更加清晰,建議在實際開發中使用@Repository、@Service和@Controller分别對實作類進行标注。

【示例2-3】接下來,通過一個案例來示範如何通過這些注解來裝配Bean。 (1)在chapter02項目的src目錄下建立一個com.ssm.annotation包,在該包中建立接口UserDao,并在接口中定義一個save()方法。

java複制代碼UserDao.java

package com.ssm.annotation;

public interface UserDao {
    public void save();
}
           

(2)在com.ssm.annotation包中建立UserDao接口的實作類UserDaoImpl,該類需要實作接口中的save()方法。

java複制代碼UserDaoImpl.java

package com.ssm.annotation;

import org.springframework.stereotype.Repository;

/**
 * 功能描述
 *
 * @author: 衍生星球
 * @date: 2023年04月14日 9:43
 */
 //使用 @Repository 注解将 UserDaoImpl 類辨別為 Spring 中的 Bean
@Repository("userDao")
public class UserDaoImpl implements UserDao {
    public void save() {
        System.out.println("userDao,save");
    }
}

           

首先使用@Repository注解将UserDaoImpl類辨別為Spring中的Bean,其寫法相當于配置檔案中 <bean id="userDao" class="com.ssm.annotation.UserDaoImpl />的編寫。然後在save()方法中列印一句話,用于驗證是否成功調用了該方法。

(3)在com.ssm.annotation包中建立接口UserService,在接口中同樣定義一個save()方法。

java複制代碼UserService.java

package com.ssm.annotation;

public interface UserService {
    public void save();
    
}
           

(4)在com.ssm.annotation包中建立UserService接口的實作類UserServiceImpl,該類需要實作接口中的save()方法。

java複制代碼UserServiceImpl.java

package com.ssm.annotation;

import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 功能描述
 *
 * @author: 衍生星球
 * @date: 2023年04月14日 14:26
 */
//使用 @ 注解将 UserServiceImpl 類辨別為 Spring 中的 Bean
@Service("userService")
public class UserServiceImpl implements UserService {
    //使用 @Resource 注解注入
    @Resource(name="userDao")
    private UserDao userDao;
    public void save() {
        this.userDao.save();
        System.out.println("執行userService.save()");
    }
}

           

首先使用@Service注解将UserServiceImpl類辨別為Spring中的Bean,這相當于配置檔案中<bean id= "userService"class="com.ssm.annotation.UserServiceImpl"/>的編寫;

然後使用@Resource注解标注在屬性userDao上,這相當于配置檔案中<property name="userDao" ref="userDao"/>的寫法;最後在該類的save()方法中調用userData中的save()方法,并輸出一句話。

(5)在com.ssm.annotation包中建立控制器類UserController。

java複制代碼UserController.java

package com.ssm.annotation;

import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

/**
 * 功能描述
 *
 * @author: 衍生星球
 * @date: 2023年04月14日 16:21
 */
//使用 @Controller 注解将 UserController 類辨別為 Spring 中的 Bean
@Controller("UserController")
public class UserController {
    //使用 @Resource 注解注入
    @Resource(name = "UserService")
    private UserService userService;
    public void save() {
        this.userService.save();
        System.out.println("運作userService.save()");
    }
}
           

首先使用@Controller注解标注了UserController類,這相當于在配置檔案中編寫<bean id="userController" class=" com.ssm.annotation.UserController"/>;

然後使用@Resource注解标注在userService屬性上,這相當于在配置檔案中編寫<property name="userService" ref=" userService"/>;最後在其save()方法中調用了userService中的save()方法,并輸出一句話。

(6)建立配置檔案beans1.xml,在配置檔案中編寫基于Annotation裝配的代碼。

java複制代碼beans1.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"
       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
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">
       
    <!-- 使用context命名空間在配置檔案中 開啟相應的注解處理器 -->
    <context:annotation-config/>
    <!-- 分别定義3個 bean 執行個體 -->
    <bean id="UserDao" class="com.ssm.annotation.UserDaoImpl" />
    <bean id="UserService" class="com.ssm.annotation.UserServiceImpl" />
    <bean id="UserController" class="com.ssm.annotation.UserController" />
</beans>
           

在<beans>元素中增加了包含context的限制資訊;然後通過配置<context: annotation-config/>來開啟注解處理器;最後分别定義了3個Bean對應的3個執行個體。與XML配置方式有所不同的是,這裡不再需要配置子元素<property>。上述Spring配置檔案中的注解方式雖然較大程度地簡化了XML檔案中Bean的配置,但仍需在Spring配置檔案中一一配置相應的Bean,為此Spring注解提供了另一種高效的注解配置方式(對包路徑下的所有Bean檔案進行掃描),其配置方式如下:

java複制代碼<context:component-scan base-package="Bean所在的包路徑" />
           

代碼進行如下替換:

java複制代碼<!-- 使用context命名空間通知 Spring 掃描指定包下所有的 Bean類,進行注解解析 -->
<context:component-scan base-package="com.ssm.annotation" />
           

(7)在com.ssm.annotation包中建立測試類AnnotationAssembleTest,在類中編寫測試方法并定義配置檔案的路徑,然後通過Spring容器加載配置檔案并擷取UserController執行個體,最後調用執行個體中的save()方法。

java複制代碼AnnotationAssembleTest.java

package com.ssm.annotation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 功能描述
 *
 * @author: 衍生星球
 * @date: 2023年04月14日 16:47
 */

public class AnnotationAssembleTest {
    private static ApplicationContext applicationContext;
    public static void main(String[] args) {
        //1.定義配置檔案路徑
        String xmlPath = "beans1.xml";
        applicationContext = new ClassPathXmlApplicationContext("xmlPath");
        //2.擷取 UserController 執行個體
        UserController userController = (UserController) applicationContext.getBean("UserController");
        //3.調用 UserController中的save()方法
        userController.save();
    }
}
           

執行程式後,控制台的輸出結果如圖所示。從中可以看到,Spring容器已成功擷取了UserController的執行個體,并通過調用執行個體中的方法執行了各層中的輸出語句,這說明已成功實作了基于Annotation來裝配Bean執行個體。

【Spring】— Spring中Bean的裝配方式

注意:上述案例中使用@Autowired注解替換@Resource注解也可以達到同樣的效果。

3.自動裝配

雖然使用注解的方式裝配Bean在一定程度上減少了配置檔案中的代碼量,但是也有企業項目中是沒有使用注解方式開發的,那麼有沒有什麼辦法既可以減少代碼量,又能夠實作Bean的裝配呢?

Spring的<bean>元素中包含一個autowire屬性,我們可以通過設定autowire的屬性值來自動裝配Bean。所謂自動裝配,就是将一個Bean自動注入其他Bean的Property中。autowire屬性有5個值,其值及說明如表所示。

【Spring】— Spring中Bean的裝配方式

【示例2-4】下面通過修改2.3.2節中的案例來示範如何使用自動裝配。 (1)修改UserServiceImpl.java和UserController.java,分别在這兩個檔案中增加類屬性的setter()方法。 (2)修改beans1.xml,将其修改成自動裝配形式。

java複制代碼	<!-- 使用bean元素的autowire屬性完成自動裝配   -->
    <bean id="UserDao" class="com.ssm.annotation.UserDaoImpl" />
    <bean id="UserService" class="com.ssm.annotation.UserServiceImpl" autowire="byName" />
    <bean id="UserController" class="com.ssm.annotation.UserController" autowire="byName" />
           

在上述配置檔案中,用于配置userService和userController的<bean>元素中除了id和class屬性外,還增加了autowire屬性,并将其屬性值設定為byName。在預設情況下,配置檔案中需要通過ref來裝配Bean,但設定了autowire="byName"後,Spring會自動尋找userServiceBean中的屬性,并将其屬性名稱與配置檔案中定義的Bean做比對。由于UserServiceImpl中定義了userDao屬性及其setter()方法,這與配置檔案中id為userDao的Bean相比對,是以Spring會自動地将id為userDao的Bean裝配到id為userService的Bean中。執行程式後,控制台的輸出結果如圖所示。

【Spring】— Spring中Bean的裝配方式

作者:衍生星球

連結:https://juejin.cn/post/7259275893796208701