1、為什么使用注解配置 Spring?
答:XML 配置文件,非編程語言語法,無法調試,使用注解配置代碼,更容易定位問題,所以注解可以替代 XML 配置文件。
2、配置步驟:
注意:Eclipse 需要先安裝 STS 插件,或者使用 STS 開發工具創建項目。
(1)導入包
注意:在基於注解的配置中,還要多拷貝一個 aop 的 jar 包。如下圖:
(2)在類的根路徑下創建一個任意名稱的 xml 文件(不能是中文)
注意:基於注解整合時,Spring 配置文件導入約束時需要多導入一個 context 名稱空間下的約束。
(3)創建一個服務類
創建一個測試的服務類,並且加入使用 @Component 注解,聲明該類允許注入到 Spring 容器
1 package com.mgy.service; 2 3 import org.springframework.stereotype.Component; 4 5 //1.使用注解配置,需要啟動,就是將創建對象的類表示為組件類 6 @Component 7 public class CustomerService { 8 9 public void save(){ 10 System.out.println("-保存數據-"); 11 } 12 13 }
(4)在 Spring 的配置文件中加入掃描注解
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 6 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> 7 <!-- 聲明掃描包以及子包的類。如果發現有組件注解的類,就創建對象,並加入到容器 --> 8 <context:component-scan base-package="com.mgy"></context:component-scan> 9 </beans>
(5)測試調用代碼
1 package com.mgy.test; 2 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5 import com.mgy.service.CustomerService; 6 7 public class CustomerServiceTest { 8 9 public static void main(String[] args) { 10 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("classpath:bean.xml"); 11 12 CustomerService customerService = context.getBean("customerService",CustomerService.class); 13 customerService.save(); 14 context.close(); 15 } 16 }
3、Spring 常用注解說明:
(1)用於對象的注解
我們將用於被掃描創建對象的注解,統稱為組件注解。
組件注解包括:@Component、@Controller、@Service、@Repository
在 context 的 jar 包里面:
問題:從功能上這四個組件注解有什么區別?
答:功能上沒有任何區別,只是概念上不一樣。
組件注解的功能都是標識類為注解的組件類,啟動 Spring 框架的程序時,將聲明了注解的類的對象注入到 Spring 容器里面。意味着,只有加了這四個注解任何一個注解的類,在程序啟動的時候,Spring 就通過配置文件指定的路徑將該路徑下的所有帶組件注解的類創建對象並且放在容器里面。功能類似原來配置文件的 <bean> 標簽。
問題:明明一個 @Component 注解就可以滿足了掃描的需要,為什么要四個呢?
答:其實 Spring 第一版注解的實現(Spring 2.5),就是使用一個 @Component。從 3.0 以后,作者認為根據分層的需要,把它拆成了四個。為了可以讓開發人員,可見即可得,一看到注解,立即知道類的性質,所以分成了四個。
@Controller:用於聲明表示層的組件注解
@Service:用於聲明服務層的組件注解
@Repository:用於聲明持久層的組件注解
@Component:用於聲明三層以外的組件注解
問題:那么,這四個注解交換使用會報錯嗎,如:持久層,放@Service 注解?
答:處理 @Controller 在 SpringMVC 里面有強制的要求,SpringMVC 的表示層必須使用@Controller 組件注解。其他情況,用亂了是不會報錯的,不過我們必須不能用亂。不遵守規范,很難和別人一起開發。
(2)用於依賴注入的注解
回顧:XML 配置文件使用 <property name="" ref="" > 實現注入的,通過注解也可以實現。
① @Autowired 注解
作用:用於給引用注入容器的對象。
屬性:request:指定注入的對象是否允許為空,如果 required=true。表示不可以為空。
使用 @Autowired 注入的三種情況
第一種:在屬性上面注入
1 package cn.mgy.action; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Controller; 5 6 import cn.mgy.service.CustomerService; 7 8 //表示層使用@Controller 9 //如果組件注解不聲明對象名,默認使用默認命名法, 10 //所謂的默認命名就是,將類的首字符小寫作為類的對象名 11 //組件注解 12 //屬性 value:作用用於指定該類對象的自定義對象名 13 @Controller(value="customerAction") 14 public class CustomerAction { 15 16 @Autowired 17 private CustomerService customerService=null; 18 19 /* 20 public void setCustomerService(CustomerService customerService) { 21 this.customerService = customerService; 22 }*/ 23 24 public void save(){ 25 System.out.println("-保存客戶-CustomerAction"); 26 customerService.save(); 27 } 28 29 }
第二種:在方法上面注入 <property>
1 package cn.mgy.action; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Controller; 5 6 import cn.mgy.service.CustomerService; 7 8 //表示層使用@Controller 9 //如果組件注解不聲明對象名,默認使用默認命名法, 10 //所謂的默認命名就是,將類的首字符小寫作為類的對象名 11 //組件注解 12 //屬性 value:作用用於指定該類對象的自定義對象名 13 @Controller(value="customerAction") 14 public class CustomerAction { 15 16 17 private CustomerService customerService=null; 18 19 //注意,如果將@Autowired方法方法上面,意思就是將對象注入到該的方法的參數 20 //意味着:Spring會自動根據參數的CustomerService類型匹配容器中對應的對象給它 21 //注意:能夠使用@Autowired注解的方法是必須有參數的 22 @Autowired 23 public void setCustomerService(CustomerService customerService) { 24 //問題:加了@Autowired的方法哎啟動的時候是否執行了? 25 //答:如果該方法沒有執行,那么this.customerService的對象從哪里來呢? 26 //加了@Autowired在啟動項目的時候是必須自動執行的 27 System.out.println("-setCustomerService已經被執行-"); 28 this.customerService = customerService; 29 } 30 31 public void save(){ 32 System.out.println("-保存客戶-CustomerAction"); 33 customerService.save(); 34 } 35 36 }
第三種:在構造方法上面注入 <constructor-arg>
1 package cn.mgy.service.impl; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Service; 5 6 import cn.mgy.dao.CustomerDAO; 7 import cn.mgy.service.CustomerService; 8 9 //業務層,使用 @Service 10 @Service 11 public class CustomerServiceImpl implements CustomerService{ 12 13 14 //如果構造方法加入@Autowired,Spring框架會自動匹配容器中是否有對應參數類的對象,將對象賦予構造方法的參數 15 //如果要使用@Autowired給構造方法注入對象,該構造方法必須要有參數 16 @Autowired 17 public CustomerServiceImpl(CustomerDAO customerDAO) { 18 super(); 19 this.customerDAO = customerDAO; 20 } 21 22 private CustomerDAO customerDAO; 23 24 @Override 25 public void save(){ 26 System.out.println("-保存客戶-CustomerService"); 27 customerDAO.save(); 28 } 29 30 }
(3)@Qualifier 注解
作用:用於指定注入的對象名,使用 @Autowired 注入對象時,@Autowired 沒有指定對象名的屬性,只能通過 @Qualifier 字段給容器中對象命名。
屬性:value:指定注入 Spring 容器中對應對象的對象名
(4)@Resource 注解
@Resource 注解是 Spring 框架支持 Sun 官方制定的 JSR-250 標准注入對象的實現。
JSR-250 就是 Sun 公司制定,對注入的對象的標准。
@Resource 功能等同於 @Autowired + @Qualifier,等同配置文件標簽 <property name="" ref="" >
@Resource 注解:用於給引用注入容器的對象,可以通過 name 屬性制定對象名
問題:在現實開發中,沒有強制要求使用 @Autowired 或者 @Resource,兩個都可以使用。但是因為 @Autowired 是 Spring 自帶的機制。所以建議使用 @Autowired.
注意事項:@Resource 只能注入方法和屬性,不能注入構造方法
問題:學習各種注解的關鍵點在哪里?
第一:必須要指定注解對應的功能含義
第二:通過查看注解的聲明,理解注解可以存放的位置以及有哪些屬性。
要學會通過注解聲明的 @Target 的類型來分析,注解可以放的位置(重點)
注入注解所在的包的位置:
除了@Resource注解是 Java 官方的標准,內置在 JDK 里面以外,Spring 內置實現的注解聲明放在 Spring-beans-4.2.9.RELEASE.jar 里面。如圖所示:
(5)@Value 注解 <value>
@Value:只能設置 標量類型 = 基礎數據類型 + 包裝類 + String
@Value 注解:注入基本數據類型以及它們的包裝類和 String 類型數據的,支持 ${} 注入 Properties 文件的鍵值對,等同於 <property name="" value="${Key}">。
屬性:value:注入基本數據類型和 String 類型數據的。
4、示例代碼 IoC 的實現
通過注解的方式,實現 Spring 框架 IoC(控制反轉)的配置
(1)導入框架需要的 jar 包
(2)創建配置文件 bean.xml
創建一個配置文件,加入指定掃描的包的路徑
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 6 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> 7 <!-- 聲明掃描包以及子包的類。如果發現有組件注解的類,就創建對象,並加入到容器 --> 8 <context:component-scan base-package="com.mgy"></context:component-scan> 9 </beans>
(3)編寫類的內容代碼
通過注解的方式,實現將類注入到容器里面。從 DAO 層開始。
持久層的實現
1 package com.mgy.dao; 2 3 public interface CustomerDAO { 4 5 public void save(); 6 7 }
1 package com.mgy.dao.impl; 2 3 import org.springframework.stereotype.Repository; 4 5 import com.mgy.dao.CustomerDAO; 6 //持久層,使用的組件注解為@Repository 7 @Repository 8 public class CustomerDAOImpl implements CustomerDAO { 9 10 @Override 11 public void save(){ 12 System.out.println("-保存客戶數據-dao"); 13 } 14 15 }
業務層的實現
1 package com.mgy.service; 2 3 public interface CustomerService { 4 5 /** 6 * 聲明一個注冊方法 7 */ 8 void reigster(); 9 }
1 package com.mgy.service.impl; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Service; 5 6 import com.mgy.dao.CustomerDAO; 7 import com.mgy.service.CustomerService; 8 //業務層,使用Service組件注解 9 @Service 10 public class CustomerServiceImpl implements CustomerService{ 11 //通過@Autowired給customerDAO引用注入Spring容器的對象 12 @Autowired 13 private CustomerDAO customerDAO; 14 15 16 public void reigster(){ 17 System.out.println("--注冊客戶-service"); 18 customerDAO.save(); 19 } 20 21 }
表示層的實現
1 package com.mgy.action; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.beans.factory.annotation.Qualifier; 5 import org.springframework.stereotype.Controller; 6 7 import com.mgy.service.CustomerService; 8 9 //表示層,使用@Controller組件注解 10 @Controller 11 public class CustomerAction { 12 //使用@Resource注解將Spring容器的對象注入給customerService引用 13 @Resource 14 private CustomerService customerService; 15 16 public void register() { 17 System.out.println("-客戶注冊-action"); 18 customerService.reigster(); 19 } 20 21 }
(4)測試代碼
1 package com.mgy.test; 2 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5 import com.mgy.action.CustomerAction; 6 7 public class CustomerServiceTest { 8 9 public static void main(String[] args) { 10 //CustomerService cs=new CustomerService(); 11 //讀取bean.xml配置文件,根據bean.xml的配置創建對象,放在容器里面 12 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("classpath:bean.xml"); 13 //從容器中獲得customerAction對象 14 CustomerAction customerAction = context.getBean("customerAction",CustomerAction.class); 15 //調用注冊方法 16 customerAction.register(); 17 //關閉容器 18 context.close(); 19 } 20 }
(5)@Qualifier 注解的使用
在 IoC 的實現的代碼的 Service 層增加一個同樣繼承 CustomerService 的類發現,再運行程序竟然報錯了。
為什么呢?
首先我們必須先理解 Spring 創建對象到注入對象的原理。
--------- Spring 對象創建流程
① 在啟動 Spring 框架的時候,框架先根據 <context:component-scan base-package="com.mgy" > 去獲得該包下的所有的類名。
② 通過反射技術,根據類名獲得類結構的組件注解,如果有就創建對象,如果沒有就忽略該類。
③ 創建對象后將對象放在 Spring 容器里面,如果不在組件注解的 value 指定對象名,使用的是默認命名法:就是取類名的首字母修改為小寫為對象名,如:CustomerDaoImpl 的對象名為 customerDaoImpl
---------- Spring 對象注入流程
Spring 將容器里面的對象注入給聲明的引用
① 首先匹配引用的類型在容器中是否存在兼容類型的對象。就是匹配引用的類型是否是父類或者相同類型的類,如果匹配的類型的對象只有一個直接將對象注入到該引用。
② 如果匹配的類型的對象不是唯一的,將引用的屬性名匹配 Spring 容器對象的對象名,如果找到對象名一樣的,就注入相同對象名的對象。
根據 Spring 對象注入流程,如果出現兩個類型一樣的對象,必須要指定對應的對象名。指定對象名的方式有兩種:
第一種:在組件注入使用 value="對象名" 指定
1 package com.mgy.service.impl; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Service; 5 6 import com.mgy.dao.CustomerDAO; 7 import com.mgy.service.CustomerService; 8 //指定注入到容器里面時,對象的對象名 9 @Service(value="customerService") 10 public class CustomerServiceImpl implements CustomerService{ 11 12 @Autowired 13 private CustomerDAO customerDAO; 14 15 16 public void reigster(){ 17 System.out.println("--注冊客戶-service"); 18 customerDAO.save(); 19 } 20 }
第二種:在注入對象給引用時指定
通過 @Qualifier 指定
現有兩個繼承 CustomerService 的類
指定 customerServiceImpl 類的對象
1 package com.mgy.action; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.beans.factory.annotation.Qualifier; 5 import org.springframework.stereotype.Controller; 6 7 import com.mgy.service.CustomerService; 8 9 10 @Controller 11 public class CustomerAction { 12 //等同使用@Autowired+@Qualifier指定注入的對象名 13 // @Resource(name="customerServiceImpl") 14 @Autowired 15 //注入指定對象名為customerServiceImpl的對象 16 @Qualifier(value="customerServiceImpl") 17 private CustomerService customerService; 18 19 public void register() { 20 System.out.println("-客戶注冊-action"); 21 customerService.reigster(); 22 } 23 }
(6)@Value 注解的使用
@Value 注解:注入基本數據類型和 String 類型數據的
配置文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 6 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> 7 <bean name="now" class="java.util.Date"></bean> 8 <!-- 聲明掃描包以及子包的類。如果發現有組件注解的類,就創建對象,並加入到容器 --> 9 <context:component-scan base-package="com.mgy"></context:component-scan> 10 11 </beans>
CustomerService 類
1 package com.mgy.service; 2 3 import java.util.Date; 4 5 import javax.annotation.Resource; 6 7 import org.springframework.beans.factory.annotation.Value; 8 import org.springframework.stereotype.Service; 9 10 @Service 11 public class CustomerService { 12 //注入基本數據類型和String類型數據的 13 @Value(value="18") 14 private int age; 15 @Value(value="張三") 16 private String name; 17 @Resource(name="now") 18 private Date birthDate; 19 20 21 public void reigster(){ 22 System.out.println("姓名:"+name); 23 System.out.println("年齡:"+age); 24 System.out.println("生日:"+birthDate); 25 26 } 27 28 }
測試代碼
1 package com.mgy.test; 2 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5 import com.mgy.service.CustomerService; 6 7 public class CustomerServiceTest { 8 9 public static void main(String[] args) { 10 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("classpath:bean.xml"); 11 12 CustomerService customerService = context.getBean("customerService",CustomerService.class); 13 customerService.reigster(); 14 context.close(); 15 } 16 17 }
5、用於設置 Spring 容器對象生命周期的注解
Spring 是通過 @Scope 注解來指定對象的生命周期的。
scope:用於設置對象的作用范圍,可選參數如下:
singleton:單例
對象出生:當程序加載配置文件創建容器時創建
對象存活:只要容器存在,一直存活
對象死亡:應用停止,容器銷毀,對象死亡
prototype:多例(原型對象)
對象出生:當程序加載配置文件創建容器時創建
對象存活:只要對象被使用,一直存活
對象死亡:對象長時間不用,會被 Java 垃圾回收機制回收
request:web 項目中,Spring 將創建的對象放在 request 作用域中
session:web 項目中,Spring 將創建的對象放在 session 作用域中
(1)@Scope 注解
作用:指定 bea 的作用范圍
屬性:value:指定范圍的值
取值:singleton、prototype、request、session
(2)示例代碼 --- 獲得單例對象
所謂的單例對象,就是每次從 Spring 容器獲得的對象就是同一個對象。默認不加 @Scope 或者聲明 @Scope(value="singleton") 都是單例
組件類:
1 package com.mgy.service; 2 3 import org.springframework.context.annotation.Scope; 4 import org.springframework.stereotype.Service; 5 6 @Service 7 //默認不寫,或者聲明value="singleton" 8 //都是聲明當前類的對象為一個單例對象 9 @Scope(value="singleton") 10 public class CustomerService { 11 12 public void reigster(){ 13 System.out.println("-客戶注冊-"); 14 } 15 }
測試代碼:
1 package com.mgy.test; 2 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5 import com.mgy.service.CustomerService; 6 7 public class CustomerServiceTest { 8 //如果兩次獲得的對象是同一個內存地址,說明是單例對象 9 public static void main(String[] args) { 10 11 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean.xml"); 12 //獲得對象1 13 CustomerService customerService = context.getBean("customerService",CustomerService.class); 14 customerService.reigster(); 15 System.out.println(customerService); 16 //獲得對象2 17 CustomerService customerService1 = context.getBean("customerService",CustomerService.class); 18 System.out.println(customerService1); 19 context.close(); 20 } 21 22 }
測試結果
兩個獲得的對象是相同的,說明該類產生的對象是單例對象
(3)示例代碼 ---- 獲得原型對象
所謂的原型對象,就是每次從 Spring 容器中獲得的對象都是重新創建的
組件類
1 package com.mgy.service; 2 3 import org.springframework.context.annotation.Scope; 4 import org.springframework.stereotype.Service; 5 6 @Service 7 //聲明value="prototype" 8 //就是當前類的對象是一個原型對象 9 @Scope(value="prototype") 10 public class CustomerService { 11 12 public void reigster(){ 13 System.out.println("-客戶注冊-"); 14 } 15 16 }
測試結果
兩次獲得對象內存不同,說明聲明周期設置為 prototype
(4)和生命周期相關的注解
① @PostConstruct 注解 等同於 <bean init-method="">
作用:用於指定初始化方法
② @PreDestroy 注解 等同於 <bean destroy-method="">
作用:用於指定銷毀方法
示例代碼:
組件類
1 package com.mgy.service; 2 3 import javax.annotation.PostConstruct; 4 import javax.annotation.PreDestroy; 5 6 import org.springframework.context.annotation.Scope; 7 import org.springframework.stereotype.Service; 8 9 @Service 10 //默認不寫,或者聲明value="singleton" 11 //都是聲明當前類唯一個單列對象 12 @Scope(value="singleton") 13 public class CustomerService { 14 //對象初始方法 15 @PostConstruct 16 public void init(){ 17 System.out.println("初始化必須調用該方法"); 18 } 19 20 21 public void reigster(){ 22 System.out.println("-客戶注冊-"); 23 } 24 25 //對象注銷前,必須調用該方法 26 @PreDestroy 27 public void destroy(){ 28 System.out.println("注銷前必須調用該方法"); 29 } 30 31 }
測試代碼
1 package com.mgy.test; 2 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5 import com.sxt.service.CustomerService; 6 7 public class CustomerServiceTest { 8 9 public static void main(String[] args) { 10 11 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean.xml"); 12 //容器啟動后,調用初始化init()方法 13 CustomerService customerService = context.getBean("customerService",CustomerService.class); 14 customerService.reigster(); 15 //容器關閉前調用 destroy()注銷方法 16 context.close(); 17 System.out.println("-容器關閉后-"); 18 } 19 20 }
6、純注解配置
用 @Configuration 注解和 @ComponentScan 注解替代 XML文件和 <context:component-scan base-package="cn.mgy"></context:component-scan> ,就可以完全不用 XML 就可以進行配置了。
替換 XML 配置文件的 @Configuration 注解 | @Configuration 配置類注解,在純注解配置中,類加了該注解,就意味着該類是 Spring 的配置類。該類的功能就是用來替代原來的 XML 配置文件。 作用:用於指定當前類是一個 Spring 配置類,當創建容器時會從該類上加載注解。獲取容器時需要使用 AnnotationConfigApplicationContext(有 @Configuration 注解的類.class) |
@ComponentScan 注解 | @ComponentScan 注解掃描類,作用就是配置掃描 Spring 組件類的路徑。功能等同原來配置文件的 <context:component-scan base-package="cn.mgy"></context:component-scan> 作用:用於指定 Spring 在初始化容器時要掃描的包。作用和在 Spring 的 XML 配置文件中的:<context:component-scan base-package="cn.mgy"></context:component-scan> 是一樣的。 屬性:basePackage:用於指定要掃描的包,和該注解中的 value 屬性作用一樣 |
@PropertySource 注解 | 作用:用於加載 .properties 文件中的配置。例如我們配置數據源時,可以把連接數據庫的信息寫到 properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。等同於 XML 配置文件中的:<context:property-placeholder file-encoding="UTF-8" location="classpath:sys.properties" /> 屬性:value[]:用於指定 properties 文件位置。如果是在類路徑下,需要寫上 classpath |
@Bean 注解 | 作用:該注解只能寫在方法上,使用此方法創建一個對象,並且放入 Spring 容器中。它就相當於我們之前在 XML 配置中介紹的 <bean 標簽> 屬性:name:給當前 @Bean 注解方法創建的對象指定一個名稱(即 bean 的 id) |
@Import 注解 | 作用:用於導入其他配置類,在引入其他配置類時,可以不用再寫 @Configuration 注解。當然,寫上也沒有問題。 屬性:value[]:用於指定其他配置類的字節碼 |
(1)簡單入門
需求:通過一個簡單的入門示例,實現創建一個配置類使用 @Configuration 注解和 @ComponentScan 注解替換 XML 文件
配置步驟:
① 創建一個 Java 項目,導入 jar 包
② 編寫組件類的代碼
組件類 CustomerService 類
1 package com.mgy.service; 2 3 import org.springframework.beans.factory.annotation.Value; 4 import org.springframework.stereotype.Component; 5 6 @Component 7 public class CustomerService { 8 9 @Value(value="1") 10 private String id; 11 @Value(value="張三") 12 private String name; 13 @Value(value="123456") 14 private String password; 15 16 public void save(){ 17 System.out.println("-保存數據-"); 18 System.out.println("編號"+id); 19 System.out.println("姓名:"+name); 20 System.out.println("密碼:"+password); 21 } 22 23 }
③ 編寫配置類代碼
通過該配置類的代碼替換掉 Spring 配置文件
1 package com.mgy.config; 2 3 import org.springframework.context.annotation.ComponentScan; 4 import org.springframework.context.annotation.Configuration; 5 6 //1.使用@Configuration聲明該類為一個Spring配置類 7 @Configuration 8 //2.使用@ComponentScan指定掃描的包路徑 9 @ComponentScan(basePackages="com.mgy") 10 public class BeanConfig { 11 12 }
④ 編寫測試代碼
1 package com.mgy.test; 2 3 import org.springframework.context.annotation.AnnotationConfigApplicationContext; 4 5 import com.mgy.config.BeanConfig; 6 import com.mgy.service.CustomerService; 7 8 public class CustomerServiceTest { 9 10 public static void main(String[] args) { 11 //注意:讀取注解配置類的容器類為AnnotationConfigApplicationContext 12 AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(BeanConfig.class); 13 14 CustomerService customerService = context.getBean("customerService",CustomerService.class); 15 customerService.save(); 16 context.close(); 17 } 18 19 }
測試結果
7、Spring 整合 Junit
以上的代碼,測試類都是通過 main 方法來測試的。當然我們最專業的單元測試工具是 Junit。你可以簡單地將 main 方法換成 Junit。代碼如下:
1 package com.mgy.test; 2 import org.junit.Test; 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 import com.mgy.service.CustomerService; 5 public class CustomerServiceTest { 6 7 //簡單實用Junit單元測試工具 8 @Test 9 public void customerService() { 10 11 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("classpath:bean.xml"); 12 CustomerService customerService = context.getBean("customerService",CustomerService.class); 13 customerService.save(); 14 context.close(); 15 } 16 }
但 Spring 框架也通過 spring-test-4.2.9.RELEASE.jar 包對 Junit 單元測試工具進行了整合。如果使用 spring-test-4.2.9.RELEASE.jar 來實現 Junit 單元測試,可以不用 ClassPathXmlApplicationContext 和 AnnotationConfigApplicationContext 獲得容器對象。可以直接使用容器中的對象。
下面就通過 spring-test-4.2.9.RELEASE.jar 來實現 Spring 框架使用 Junit 單元測試工具。
(1)測試基於 XML 的配置
就是使用 spring-test-4.2.9.RELEASE.jar 的功能對 XML 配置文件配置的 Spring 項目進行單元測試。
① 創建項目導入包
② 編寫一個簡單的 CustomerService 類
1 package com.mgy.service; 2 3 import java.util.Date; 4 5 public class CustomerService { 6 7 private int age; 8 private String name; 9 private Date birthDate; 10 11 public void setAge(int age) { 12 this.age = age; 13 } 14 15 public void setName(String name) { 16 this.name = name; 17 } 18 19 public void setBirthDate(Date birthDate) { 20 this.birthDate = birthDate; 21 } 22 23 public void reigster(){ 24 System.out.println("姓名:"+name); 25 System.out.println("年齡:"+age); 26 System.out.println("生日:"+birthDate); 27 } 28 }
③ 編寫 Spring 配置文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd "> 5 <bean name="now" class="java.util.Date"></bean> 6 <bean name="customerService" class="com.mgy.service.CustomerService"> 7 <!-- 一個property標簽匹配一個set方法 --> 8 <property name="name" value="張三"></property> 9 <property name="age" value="15"></property> 10 <property name="birthDate" ref="now"></property> 11 </bean> 12 13 </beans>
④ Junit 測試
1 package com.mgy.test; 2 3 import org.junit.Test; 4 import org.junit.runner.RunWith; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.test.context.ContextConfiguration; 7 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 8 9 import com.mgy.service.CustomerService; 10 //指定Junit之前測試之前,加入Spring框架啟動的邏輯代碼 11 @RunWith(SpringJUnit4ClassRunner.class) 12 //指定Spring啟動必須的配置文件 13 //注意:配置文件通過locations指定 14 @ContextConfiguration(locations="classpath:bean.xml") 15 public class CustomerServiceTest { 16 17 //獲得Spring容器中的對象 18 @Autowired 19 private CustomerService customerService; 20 21 22 //直接調用@Autowired獲得容器對象 23 @Test 24 public void reigster() { 25 customerService.reigster(); 26 27 } 28 29 }
(2)測試基於純注解的配置
就是通過 spring-test-4.2.9.RELEASE.jar 對純注解配置的 Spring 項目進行單元測試
① 創建一個項目並導入包
② 編寫一個簡單的組件類
package com.mgy.service; import java.util.Date; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service public class CustomerService { @Value("12") private int age; @Value("張三") private String name; @Autowired @Qualifier(value="now") private Date birthDate; public void setAge(int age) { this.age = age; } public void setName(String name) { this.name = name; } public void setBirthDate(Date birthDate) { this.birthDate = birthDate; } public void reigster(){ System.out.println("姓名:"+name); System.out.println("年齡:"+age); System.out.println("生日:"+birthDate); } }
③ 編寫一個配置類
1 package com.mgy.config; 2 3 import java.util.Date; 4 5 import org.springframework.context.annotation.Bean; 6 import org.springframework.context.annotation.ComponentScan; 7 import org.springframework.context.annotation.Configuration; 8 9 @Configuration 10 @ComponentScan(basePackages="com.sxt") 11 public class BeanConfig { 12 13 @Bean 14 public Date now() { 15 return new Date(); 16 } 17 }
④ 使用 Junit 測試
1 package com.mgy.test; 2 3 import org.junit.Test; 4 import org.junit.runner.RunWith; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.test.context.ContextConfiguration; 7 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 8 9 import com.mgy.config.BeanConfig; 10 import com.mgy.service.CustomerService; 11 //指定Junit之前測試之前,加入Spring框架啟動的邏輯代碼 12 @RunWith(SpringJUnit4ClassRunner.class) 13 //指定Spring啟動必須的配置文件 14 //注意:配置類通過classes指定 15 @ContextConfiguration(classes=BeanConfig.class) 16 public class CustomerServiceTest { 17 18 //獲得Spring容器中的對象 19 @Autowired 20 private CustomerService customerService; 21 22 //直接調用@Autowired獲得容器對象 23 @Test 24 public void reigster() { 25 customerService.reigster(); 26 27 } 28 }
8、總結
(1)首先要知道注解的配置與 XML 的配置功能一樣
(2)理解注解的配置與 XML 的配置分別有什么作用
------ 組件注解
作用:用於聲明類為一個注解類,Spring 會在啟動的時候,根據 <context:component-scan /> 掃描的包的范圍,將這些加了組件注解的類創建對象,並且放在容器里面
@Component、@Controller、@Service、@Repository
--- 依賴注入(不用 new)
@Autowired 作用:用於依賴注入,將容器里面的對象注入到對應的屬性、構造方法的參數、方法的參數 等同於 <property name="屬性名" ref=""> <constractor-arg name="" ref="">
@Qualifier 作用:在容器中同一個類型的對象出現多個,可以通過 @Qualifier 指定對象名來獲得指定的對象
@Resource(name="對象名") 等同於 @Autowired + @Qualifier
@Resource 的作用也是用於注入對象的,是 Java JSR250 標准的支持。注意:該注解不能將對象注入到構造方法的參數上面
@Value 作用:如果注入的不是對象,而是一個標量類型,可以使用 @Value
--- 聲明周期
@Scope 作用:用於指定創建的對象的生命周期,是單例、原型
注意:@Scope 如果放在方法上面,必須要和 @Bean 注解結合使用
@PostConstruct 作用:用於指定初始化方法
@PreDestroy 作用:用於指定容器銷毀之前執行的方法
--- 純注解的支持(替換配置文件)
@Configuration 作用:用於聲明類是一個配置類
@ComponentScan 作用:用於掃描組件類創建對象到容器 <context:component-scan>
@PropertySource 作用:用於對 Properties 文件的支持 <context:property-placeholder>
@Bean 作用:用於將非組件類的對象加入到 Spring 容器中 <bean>
@Import(了解)作用:用於導入其他的配置類的配置
--- 對 Junit 的整合的支持(了解)
@RunWith(SpringJUnit4ClassRunner.class) 作用:用於指定 Junit 測試之前,加入 Spring 框架啟動的邏輯代碼
@ContextConfiguration 作用:用於指定整合時配置文件(locations="classpath:bean.xml")或文件類(classes=BeanConfig.class)