Spring進階案例之註解和IoC案例
一、常見的註解分類及其作用
從此前的基於xml的IoC開發案例和依賴注入案例中,我們可以將xml配置歸納為:
<bean id="" class="" scope="" init-method = "" destroy-method = "">
<property name = "" value = "" | ref = ""></property>
</bean>
註解按照作用可以分為四類:
1.用於建立物件的註解:相當於xml配置的bean標籤
建立物件的註解有如下幾個:
註解 | 作用 | 屬性 |
---|---|---|
@Component | 把當前類物件存入Spring容器中 | value: 用於指定bean的id。當不寫value屬性時,預設值是當前類名,且首字母改小寫 |
@Controller | 一般用在表現層建立bean | 同上 |
@Service | 一般用在業務層建立bean | 同上 |
@Repository | 一般用在持久層建立bean | 同上 |
最後三個註解的作用和屬性與Component註解一模一樣,他們是Spring框架為我們提供明確三層架構的註解,可以使三層架構更加清晰。
如果我們在AccoutServiceImpl類上加上@Component("accountService")或者@Service("accountService"),都可以起到將AccountServiceImpl類的物件加入的IoC容器中的效果。此時,ui.Client類中的main方法還不能執行:
public static void main(String[] args) {
//驗證依賴注入
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");
System.out.println(accountService);
}
會顯示No bean named 'accountService' ,這是因為我還沒有對Spring要掃描的包進行配置,如果不配置,Spring是不知道哪些類需要掃描註解。
<!-- 配置Spring在建立容器時要掃描的包,在一個名為context名稱空間的約束中進行配置-->
<context:component-scan base-package="service"></context:component-scan>
<context:component-scan base-package="dao"></context:component-scan>
此時,專案結構為:
dao包:
public interface IAccountDao
dao.impl包:
@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao
service包:
public interface IAccountService
service.impl包:
@Service("accountService")
public class AccountServiceImpl implements IAccountService
ui包:
public class Client
2.用於注入物件的註解:相當於xml配置的bean標籤中property標籤,使用註解進行注入時,不再需要set方法
如果我們需要呼叫accountService中的saveAccount方法,就需要對AccountServiceImpl類中的accountDao成員變數進行注入。同時需要在AccountDaoImpl類的accountDao變數上加上@Autowired("accountDao")註解。用於注入資料的註解有如下幾個:前三個註解只能注入其他bean型別的注入,基本型別和String型別的注入無法通過它們來實現。集合型別的注入只能通過xml配置來實現,不能通過註解來實現。
註解 | 作用 | 屬性 |
---|---|---|
@Autowired | 自動按照型別注入,可以出現在變數上,也可以出現在在方法上。 | 無 |
@Qualifier | 按照類中注入的基礎之上再按照名稱注入。在給類成員注入時不能單獨注入,在給方法引數注入時可以單獨注入 | value:用於指定注入bean的id |
@Resource | 直接按照bean的id注入,可以單獨使用 | name:用於指定注入bean的id |
@Value | 用於注入String型別和基本型別 | value:用於指定注入資料的值,可以使用Spring中的el表示式(SpEL,寫法為:${表示式}) |
這個時候,我們在ui.Client類的main方法中,就可以執行saveAccount方法了。
public static void main(String[] args) {
//驗證依賴注入
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");
System.out.println(accountService);
IAccountDao accountDao = applicationContext.getBean("accountDao", IAccountDao.class);
System.out.println(accountDao);
//呼叫saveAccount方法
accountService.saveAccounts();
}
在使用@Autowired註解時,需要注意的是:
- 只要IoC容器中有唯一的一個bean物件和要注入的變數型別匹配,就可以注入成功。
- 如果IoC容器中任何bean物件和要注入的變數型別都不匹配,就會報錯。
- 如果IoC容器中有多個bean物件和要注入的變數型別匹配,則按變數名稱和bean類名進行匹配,若有唯一一個匹配,則注入成功,否則注入失敗。
例如,在dao.impl包下,有兩個IAccountDao介面的實現類,分別是是AccountDaoImpl1和AccountDaoImpl2,在這兩個類上分別加入註解@Repository("accountDao1")和@Repository("accountDao2")。
此時,專案結構為:
dao包:
public interface IAccountDao
dao.impl包:
@Repository("accountDao1")
public class AccountDaoImpl1 implements IAccountDao
@Repository("accountDao2")
public class AccountDaoImpl2 implements IAccountDao
service包:
public interface IAccountService
service.impl包:
@Service("accountService")
public class AccountServiceImpl implements IAccountService
ui包:
public class Client
如果還使用Autowired註解對AccountServiceImpl類中的accountDao變數進行注入,就會報錯。這個時候,有三種方式可以選擇:
-
只使用@Autowired註解,並修改accountDao變數名為accountDao1,此時注入的是dao.impl.AccountDaoImpl1
-
同時使用@Autowired和@Qualifier("accountDao2")註解,變數名可以任意,注入的是dao.impl.AccountDaoImpl2
-
只使用@Resource(name = "accountDao1")註解,變數名可以任意,注入的是dao.impl.AccountDaoImpl1
//方法一 @Autowired private IAccountDao accountDao1; //方法二 @Autowired @Qualifier("accountDao2") private IAccountDao accountDao22; //方法三 @Resource(name = "accountDao1") private IAccountDao accountDao;
為了看的更清楚,我們進行如下改造:
//AccountDaoImpl1和AccountDaoImpl2中的saveAccounts方法:
public void saveAccounts() {
System.out.println(this.getClass());
System.out.println("向資料庫寫入賬戶資料!!!");
}
//AccountServiceImpl中的saveAccounts方法:
public void saveAccounts() {
System.out.println("執行儲存賬戶操作");
//呼叫持久層介面函式
accountDao.saveAccounts();
accountDao1.saveAccounts();
accountDao22.saveAccounts();
}
//Client類中的main方法:
public static void main(String[] args) {
//驗證依賴注入
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");
//呼叫saveAccount方法
accountService.saveAccounts();
}
輸出為:
執行儲存賬戶操作
class dao.impl.AccountDaoImpl1
向資料庫寫入賬戶資料!!!
class dao.impl.AccountDaoImpl1
向資料庫寫入賬戶資料!!!
class dao.impl.AccountDaoImpl2
向資料庫寫入賬戶資料!!!
3.用於改變物件作用範圍的註解:相當於xml配置的bean標籤中的scope屬性
如果我們要改變bean的作用範圍,就需要用到scope屬性:
註解 | 作用 | 屬性 |
---|---|---|
@Scope | 用於指定bean的作用範圍 | value: 指定範圍的取值。常用取值:singleton(單例,也是預設值)、prototype(多例)、 |
例如,我們在AccountServiceImpl2類上加上註解@Scope("prototype"),然後在main方法中執行:
IAccountDao accountDao11 = applicationContext.getBean("accountDao1", IAccountDao.class);
System.out.println(accountDao11);
IAccountDao accountDao12 = applicationContext.getBean("accountDao1", IAccountDao.class);
System.out.println(accountDao12);
IAccountDao accountDao21 = applicationContext.getBean("accountDao2", IAccountDao.class);
System.out.println(accountDao21);
IAccountDao accountDao22 = applicationContext.getBean("accountDao2", IAccountDao.class);
System.out.println(accountDao22);
可以看到輸出中,前兩個accountDao是同一個物件,後兩個是不同物件:
4.用於改變物件生命週期的註解:相當於xml配置的bean標籤中的init-method屬性和destroy-method屬性
註解 | 作用 | 使用位置 |
---|---|---|
@PostConstruct | 用於指定初始化方法 | 用在方法上 |
@PreDestroy | 用於指定銷燬方法 | 用在方法上 |
注意:多例物件的銷燬仍然由JVM執行,無法通過關閉容器來銷燬
二、基於XML的IoC案例
1.準備工作
這個IoC案例,主要演示對資料庫的crud操作,所以首先需要建立資料庫,sql檔案如下:
create table account(
id int primary key auto_increment,
name varchar(40),
money float
)character set utf8 collate utf8_general_ci;
insert into account(name,money) values('aaa',1000);
insert into account(name,money) values('bbb',1000);
insert into account(name,money) values('ccc',1000);
整個專案的結構如下:
IAccountDao和IAccountService這兩個介面類中的方法如下,因為只是演示,簡單起見這兩個介面中的方法一模一樣:
/** 查詢所有 */
List<Account> findAllAccounts();
/** 根據id查詢賬戶 */
Account findAccountById(Integer id);
/** 儲存賬戶 */
void saveAccount(Account account);
/** 修改賬戶*/
void updateAccount(Account account);
/** 根據id刪除賬戶 */
void deleteAccountById(Integer id);
我們還需要一個實體類用於封裝查詢結果,簡單起見,省略了get和set方法,以及toString方法:
public class Account implements Serializable {
private Integer id;
private String name;
private float money;
//還有set方法和get方法,以及toString方法沒有顯示
}
2.編寫介面實現類
public class AccountDaoImpl implements IAccountDao {
private QueryRunner queryRunner;
//由於需要通過配置檔案對QueryRunner進行注入,所以需要提供set方法
public void setQueryRunner(QueryRunner queryRunner) {
this.queryRunner = queryRunner;
}
@Override
public List<Account> findAllAccounts() {
try {
return queryRunner.query("select * from account",
new BeanListHandler<>(Account.class));
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public Account findAccountById(Integer id) {
try {
return queryRunner.query("select * from account where id = ?",
new BeanHandler<>(Account.class), id);
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void saveAccount(Account account) {
try {
queryRunner.update("insert into account(name, money) values (?,?)",
account.getName(), account.getMoney());
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void updateAccount(Account account) {
try {
queryRunner.update("update account set name=?, money=? where id = ?",
account.getName(), account.getMoney(), account.getId());
}catch (Exception e){
throw new RuntimeException(e);
}
}
@Override
public void deleteAccountById(Integer id) {
try {
queryRunner.update("delete from account s where id = ?", id);
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao;
//set方法用於注入
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public List<Account> findAllAccounts() {
return accountDao.findAllAccounts();
}
@Override
public Account findAccountById(Integer id) {
return accountDao.findAccountById(id);
}
@Override
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
@Override
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
@Override
public void deleteAccountById(Integer id) {
accountDao.deleteAccountById(id);
}
}
3.編寫配置檔案
前面的部分都不用太關心,只需要瞭解即可。QueryRunner是java程式設計中的資料庫操作實用工具類DBUtils中的一個核心類,可以用於連線資料庫執行SQL語句。beans.xml檔案是Spring的配置檔案,重點應該放在配置檔案上。
<?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">
<!-- 配置service -->
<bean id = "accountService" class="com.crud.service.impl.AccountServiceImpl">
<!-- 注入dao -->
<property name="accountDao" ref="accountDao"></property>
</bean>
<!-- 配置dao -->
<bean id = "accountDao" class="com.crud.dao.impl.AccountDaoImpl">
<!-- 注入queryRunner -->
<property name="queryRunner" ref="queryRunner"></property>
</bean>
<!-- 配置queryRunner,必須是多例物件,否則會出現執行緒安全問題 -->
<bean id = "queryRunner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!-- 注入資料來源 -->
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<!-- 配置資料來源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 配置連線資料庫的必備資訊 -->
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring"></property>
<property name="user" value="root"></property>
<property name="password" value="12345678"></property>
</bean>
</beans>
配置檔案中需要注意的是,因為每一個連線都會用到QueryRunner物件,所以必須是多例模式,否則就會出現執行緒安全問題。此外,在配置資料來源時,property中的value可以從其他檔案中讀取。該配置檔案,基本上綜合了之前講的用xml進行依賴注入。
例如:
首先在src/main/resources目錄下編寫:jdbc.properties檔案
jdbc.driver = com.mysql.cj.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/spring
jdbc.user = root
jdbc.password = 12345678
然後對beans.xml檔案進行修改:
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置資料來源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 配置連線資料庫的必備資訊 -->
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
對於maven的配置檔案pom.xml,主要需要匯入的包有:Spring、dbutils(用於執行sql語句)、mysql、c3p0(用於資料來源)、junit(用於單元測試)
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
3.單元測試
編寫AccountServiceTest測試類用於測試,只測試能否正常執行crud操作,這裡只演示了測試查詢所有方法:
public class AccountServiceTest {
@Test
public void testFinaAll() {
//1.獲取容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//2.從容器中獲取業務層物件
IAccountService accountService = applicationContext.getBean("accountService", IAccountService.class);
//3.執行方法
List<Account> accounts = accountService.findAllAccounts();
for (Account account : accounts) {
System.out.println(account);
}
}
}
三、基於註解和xml的IoC案例
1.修改AccountServiceImpl和AccountDaoImpl類
在上述案例中,採用的xml進行依賴注入。本案例中,使用註解的方式進行依賴注入,所以不再需要main方法。這兩個類僅進行如下修改,其餘部分不變:
@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao {
@Autowired
private QueryRunner queryRunner;
}
@Service("accountService")
public class AccountServiceImpl implements IAccountService {
@Autowired
private IAccountDao accountDao;
}
2.修改beans.xml配置檔案
和之前一樣,要告知Spring要掃描的包,所以約束空間要加入context名稱空間,此外之前service和dao的xml配置就不再需要了,但是和連線資料庫相關的QueryRunner的配置仍然需要。
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置Spring在建立容器時要掃描的包,在一個名為context名稱空間的約束中進行配置-->
<context:component-scan base-package="com.crud"></context:component-scan>
<!-- 配置queryRunner,必須是多例物件,否則會出現執行緒安全問題 -->
<bean id = "queryRunner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!-- 注入資料來源 -->
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<!-- 配置資料來源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 配置連線資料庫的必備資訊 -->
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring"></property>
<property name="user" value="root"></property>
<property name="password" value="12345678"></property>
</bean>
</beans>
3.測試執行
由於多個單元測試都需要用到accountService物件,所以這裡抽取出來作類物件,這樣就只需要初始化一次。
public class AccountServiceTest {
private ApplicationContext applicationContext;
private IAccountService accountService;
//手動獲取accountService物件
@Before
public void init(){
//1.獲取容器
applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//2.從容器中獲取業務層物件
accountService = applicationContext.getBean("accountService", IAccountService.class);
}
@Test
public void testFinaAll() {
//3.執行方法
List<Account> accounts = accountService.findAllAccounts();
for (Account account : accounts) {
System.out.println(account);
}
}
}
四、基於純註解的IoC案例
1.配置類
如果不寫xml配置檔案,我們如何去指定Spring的相關配置呢?這個時候就需要一個配置類來代替xml配置檔案。在src目錄下,新建com.crud.conf包,該包下新建配置類SpringConfig。依照前面註解結合xml配置檔案的案例。我們需要解決的問題有:
1.告知Spring容器要掃描的包,對應<context:component-scan>標籤
2.配置queryRunner
3.配置資料來源
2.Spring新註解
註解 | 作用 | 屬性 |
---|---|---|
@Configuration | 指定當前類是一個配置類。 | 無 |
@Import | 用於匯入其他的配置類 | value:用於指定其他配置類的位元組碼 |
@ComponentScan/@ComponentScans | 指定Spring在建立容器時要掃描的包 | value/basePackages:用於指定包 |
@Bean | 把當前方法的返回值作為Bean物件存入IoC容器 | name:用於指定bean的id,不寫是預設值就是當前方法的名稱 |
@PropertySource | 用於指定要使用的properties檔案的位置 | value:指定檔案的名稱和路徑,classpath關鍵字表示類路徑 |
3.新註解的使用
整個專案的結構如下:
接下來我們一個一個詳細理解這些註解的作用:
- @Configuration註解用於指定配置類,一般所有的配置類都需要加上這個註解。但是也有例外:如果不寫@Configuration註解,那麼會將Spring的IoC容器會將AnnotationConfigApplicationContext構造方法中的引數作為配置類;因此,作為引數傳入的配置類的@Configuration註解可用不寫。
- @Import註解用於匯入其他配置類。在實際開發過程中,可能不止一個配置類。例如和Spring相關的配置作為一個住配置類,和連線資料庫相關的配置類作為一個子類。當使用@Import註解之後,使用@Import註解的配置類就是主配置類,匯入的配置類就是子配置類。此時,子類就不需要再寫@Configuration註解。
- @ComponentScan/@ComponentScans註解用於指定Spring在建立容器時要掃描的包,前者用於指定一個包,後者用於指定多個包。這就相當於xml配置檔案中的<context:component-scan>中的basePackages屬性。
- @Bean註解用於把當前方法的返回值作為Bean物件存入IoC容器。當方法上有@Bean註解時,Spring會在容器中查詢有沒有和引數對應的可用bean物件,查詢方式和@Autowired註解的方式相同。這就相當於xml配置檔案中的Bean標籤。
- @PropertySource註解用於指定要使用的properties檔案的位置。
最終這些註解在程式碼中的使用如下:
@Configuration
@ComponentScan("com.crud")
@Import(JdbcConfig.class)
/** 主配置類 */
public class SpringConfig { }
/** jdbc配置類 */
@PropertySource("classpath:jdbcConfig.properties")
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.user}")
private String user;
@Value("${jdbc.password}")
private String password;
/** 根據資料來源建立QueryRunner物件,必須是多例的,否則會出現執行緒安全問題 */
@Bean("queryRunner")
@Scope("prototype")
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
/** 建立資料來源物件 */
@Bean("dataSource")
public DataSource createDataSource(){
try{
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass(driver);
comboPooledDataSource.setJdbcUrl(url);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password);
return comboPooledDataSource;
}catch (Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
4.測試
有一點需要修改,就是在獲取容器時,不能再使用ClassPathXmlApplicationContext類,而應該使用AnnotationConfigApplicationContext,如下:
//引數是類位元組碼,可以傳入多個類的位元組碼,作為引數的配置類可以不寫@Configuration註解
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
5.@Bean註解的查詢方式
@Bean建立Bean物件的方式後的查詢方法和@Autowired註解相同,如果有多個名稱匹配,就需要用到@Qualifier註解來指定用哪個匹配。例如,jdbcConfig類可以修改為如下:
/**
* 根據資料來源建立QueryRunner物件,必須是多例的,否則會出現執行緒安全問題
* @Qualifier註解用於解決多個型別匹配時的問題
* @param dataSource
* @return
*/
@Bean("queryRunner")
@Scope("prototype")
public QueryRunner createQueryRunner(@Qualifier("ds2") DataSource dataSource){
return new QueryRunner(dataSource);
}
/**
* 建立資料來源物件
* @return
*/
@Bean("ds1")
public DataSource createDataSource(){
try{
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass(driver);
comboPooledDataSource.setJdbcUrl(url);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password);
return comboPooledDataSource;
}catch (Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Bean("ds2")
public DataSource createDataSource1(){
try{
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass(driver);
comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password);
return comboPooledDataSource;
}catch (Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}
}
五、Spring整合Junit
在測試類中,獲取Spring的IoC容器和AccountService物件時,我們一直都是手動獲取。有沒有辦法讓Spring為我們自動注入呢?當然是有的,但是如果直接沒有在accountService成員變數之上,加上@Autowired註解,執行就會報錯。這是因為:
1.Junit單元測試中,沒有main方法也能執行。因為Junit整合了一個main方法,該方法會判斷當前測試類中哪些方法有@Test註解,Junit就會執行有@Test註解的方法。
2.Junit不會管使用者使用何種框架,因此在執行測試方法是,junit不知道使用者是否使用Spring框架,所以也就不會讀取配置檔案/配置來建立Spring的IoC核心容器。因此在測試類中,就算寫了@Autowired註解,也無法實現注入。
因此要在Junit中使用Spring,就要遵循一下步驟:
1.匯入Spring整合junit的配置
在pom.xml配置檔案中<dependencies>的匯入:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2.使用Junit提供的@RunWith註解,將原有的main方法替換為Spring提供的main方法
在AccountServiceTest類之上加上@RunWith(SpringJUnit4ClassRunner.class)註解
3.告知Spring的執行器,是基於xml還是註解進行配置,並說明位置
在AccountServiceTest類之上加上@ContextConfiguration(classes = SpringConfig.class)註解。對於@ContextConfiguration註解,屬性locations用於指定xml配置檔案的位置,要加上classpath關鍵字表示在類路徑下,屬性classes:指定配置類所在的位置。
4.注意事項
當Spring的版本是5.x時,junit的版本必須是4.12及以上版本。最終整個測試類程式碼如下:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
@Autowired
private IAccountService accountService;
@Test
public void testFinaAll() {
//3.執行方法
List<Account> accounts = accountService.findAllAccounts();
for (Account account : accounts) {
System.out.println(account);
}
}
}