Spring之使用注解實例化Bean並注入屬性


1.准備工作

(1)導入jar包

除了上篇文章使用到的基本jar包外,還得加入aop的jar包,所有jar包如下

所需jar包

(2)配置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 http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 開啟注解掃描,到包里面掃描類、屬性、方法上是否有注解 --> <context:component-scan base-package="com.codeliu"/> </beans> 

2.注解實例化Bean

(1)實例化Bean有四個注解

  • @Component
  • @Service:業務層
  • @Controller:WEB層
  • @Repository:持久層

雖然分了層,但目前這四個注解的功能是一樣的。

@Service(value = "user") //相當於bean標簽中的id,四種方式功能一樣 // @Component(value = "user") // @Controller(value = "user") // @Repository(value = "user") @Scope(value = "singleton") public class User { public void print() { System.out.println("user......"); } } 
    @Test /** * 使用注解實例化User類 */ public void testUser() { // 讀取配置文件 @SuppressWarnings("resource") ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); User user = (User)context.getBean("user"); user.print(); }

bean的作用域配置

  Spring中可以使用scope屬性來配置bean的作用域:

  singleton:單例,在初始化配置文件時生成單例bean對象

  prototype:原型的,在初始化配置文件時不生成bean對象,使用時返回不同的bean對象

  request:web環境下每一個request請求都會返回一個不同的bean,只在本次請求中有效

  session:web環境下每一個request請求都會返回一個不同的bean,在session中有效

3.注解為屬性賦值

首先來個UserDao

@Component(value = "userDao") public class UserDao { public void print() { System.out.println("userdao......"); } } 

再來個service

@Service(value = "userService") public class UserService { // 注入對象類型的屬性,不用提供set方法 // 1.使用自動裝配 // @Autowired // 為byType類型,如果有多個相同類型的,得配合@Qualifier注解 // private UserDao userDao; // 2.不使用自動裝配 @Resource(name = "userDao") private UserDao userDao; // 注入普通類型的屬性 @Value(value = "CodeTiger") private String name; public void print() { System.out.println("UserService......"); userDao.print(); System.out.println(name); } } 

為屬性賦值,我們可以使用自動裝配,也可以手動賦值。

    @Test /** * 使用注解注入屬性 */ public void testUserService() { @SuppressWarnings("resource") ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); UserService service = (UserService)context.getBean("userService"); service.print(); } 

4.注解和xml結合使用

當然我們也可以同時使用注解和xml,一般我們在xml中實例化Bean,使用注解為屬性賦值。


Spring@Autowired注解與自動裝配

1   配置文件的方法

我們編寫spring 框架的代碼時候。一直遵循是這樣一個規則:所有在spring中注入的bean 都建議定義成私有的域變量。並且要配套寫上 get 和 set方法。

Boss 擁有 Office 和 Car 類型的兩個屬性:   
  
清單 3. Boss.java

 

[java]  view plain  copy
 
 
 
  1. package com.baobaotao;     
  2.     
  3. public class Boss {     
  4.     private Car car;     
  5.     private Office office;     
  6.     
  7.     // 省略 get/setter     
  8.     
  9.     @Override    
  10.     public String toString() {     
  11.         return "car:" + car + "/n" + "office:" + office;     
  12.     }     
  13. }     
   System.out.println必須實現toString方法
  
我們在 Spring 容器中將 Office 和 Car 聲明為 Bean,並注入到 Boss Bean 中:下面是使用傳統 XML 完成這個工作的配置文件 beans.xml:   
  
清單 4. beans.xml 將以上三個類配置成 Bean   
                   
[xhtml]  view plain  copy
 
 
 
  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      
  5. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">     
  6.     <bean id="boss" class="com.baobaotao.Boss">     
  7.         <property name="car" ref="car"/>     
  8.         <property name="office" ref="office" />     
  9.     </bean>     
  10.     <bean id="office" class="com.baobaotao.Office">     
  11.         <property name="officeNo" value="002"/>     
  12.     </bean>     
  13.     <bean id="car" class="com.baobaotao.Car" scope="singleton">     
  14.         <property name="brand" value=" 紅旗 CA72"/>     
  15.         <property name="price" value="2000"/>     
  16.     </bean>     
  17. </beans>    
當我們運行以下代碼時,控制台將正確打出 boss 的信息:   
  
清單 5. 測試類:AnnoIoCTest.java   
                   
[java]  view plain  copy
 
 
 
  1. import org.springframework.context.ApplicationContext;     
  2. import org.springframework.context.support.ClassPathXmlApplicationContext;     
  3. public class AnnoIoCTest {     
  4.     
  5.     public static void main(String[] args) {     
  6.         String[] locations = {"beans.xml"};     
  7.         ApplicationContext ctx =      
  8.             new ClassPathXmlApplicationContext(locations);     
  9.         Boss boss = (Boss) ctx.getBean("boss");     
  10.         System.out.println(boss);     
  11.     }     
  12. }     
  13.       

  
這說明 Spring 容器已經正確完成了 Bean 創建和裝配的工作。   

 

2   @Autowired 

Spring 2.5 引入了 @Autowired 注釋,它可以對類成員變量、方法及構造函數進行標注,完成自動裝配的工作。 通過 @Autowired的使用來消除 set ,get方法。

要實現我們要精簡程序的目的。需要這樣來處理: 
* 在applicationContext.xml中加入: 

[c-sharp]  view plain  copy
 
 
 
  1. <!-- 該 BeanPostProcessor 將自動對標注 @Autowired 的 Bean 進行注入 -->     
  2.   <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>  

  Spring 通過一個 BeanPostProcessor 對 @Autowired 進行解析,所以要讓 @Autowired 起作用必須事先在 Spring 容器中聲明 AutowiredAnnotationBeanPostProcessor Bean。   

* 修改在原來注入spirng容器中的bean的方法。 
     在域變量上加上標簽@Autowired,並且去掉 相應的get 和set方法

  清單 6. 使用 @Autowired 注釋的 Boss.java                   

[java]  view plain  copy
 
 
 
  1. package com.baobaotao;     
  2. import org.springframework.beans.factory.annotation.Autowired;     
  3.     
  4. public class Boss {     
  5.     
  6.     @Autowired    
  7.     private Car car;     
  8.     
  9.     @Autowired    
  10.     private Office office;     
  11.     
  12.     …     
  13. }     

* 在applicatonContext.xml中 把原來 引用的<porpery >標簽也去掉。 

[xhtml]  view plain  copy
 
 
 
  1.             
  2. <?xml version="1.0" encoding="UTF-8" ?>     
  3. <beans xmlns="http://www.springframework.org/schema/beans"    
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans      
  6. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">     
  7.     
  8.     <!-- 該 BeanPostProcessor 將自動起作用,對標注 @Autowired 的 Bean 進行自動注入 -->     
  9.     <bean class="org.springframework.beans.factory.annotation.     
  10.         AutowiredAnnotationBeanPostProcessor"/>     
  11.     
  12.     <!-- 移除 boss Bean 的屬性注入配置的信息 -->     
  13.     <bean id="boss" class="com.baobaotao.Boss"/>     
  14.       
  15.     <bean id="office" class="com.baobaotao.Office">     
  16.         <property name="officeNo" value="001"/>     
  17.     </bean>     
  18.     <bean id="car" class="com.baobaotao.Car" scope="singleton">     
  19.         <property name="brand" value=" 紅旗 CA72"/>     
  20.         <property name="price" value="2000"/>     
  21.     </bean>     
  22. </beans>    

 這樣,當 Spring 容器啟動時,AutowiredAnnotationBeanPostProcessor 將掃描 Spring 容器中所有 Bean,當發現 Bean 中擁有 @Autowired 注釋時就找到和其匹配(默認按類型匹配)的 Bean,並注入到對應的地方中去。   
  
按照上面的配置,Spring 將直接采用 Java 反射機制對 Boss 中的 car 和 office 這兩個私有成員變量進行自動注入。所以對成員變量使用 @Autowired 后,您大可將它們的 setter 方法(setCar() 和 setOffice())從 Boss 中刪除。   
  
當然,您也可以通過 @Autowired 對方法或構造函數進行標注,如果構造函數有兩個入參,分別是 bean1 和 bean2,@Autowired 將分別尋找和它們類型匹配的 Bean,將它們作為 CountryService (Bean1 bean1 ,Bean2 bean2) 的入參來創建 CountryService Bean。來看下面的代碼:  對方法

 

[java]  view plain  copy
 
 
 
  1. package com.baobaotao;     
  2.     
  3. public class Boss {     
  4.     private Car car;     
  5.     private Office office;     
  6.     
  7.      @Autowired    
  8.     public void setCar(Car car) {     
  9.         this.car = car;     
  10.     }     
  11.       
  12.     @Autowired    
  13.     public void setOffice(Office office) {     
  14.         this.office = office;     
  15.     }     
  16.     …     
  17. }     

 

這時,@Autowired 將查找被標注的方法的入參類型的 Bean,並調用方法自動注入這些 Bean。而下面的使用方法則對構造函數進行標注:   

[java]  view plain  copy
 
 
 
  1. package com.baobaotao;     
  2.     
  3. public class Boss {     
  4.     private Car car;     
  5.     private Office office;     
  6.       
  7.     @Autowired    
  8.     public Boss(Car car ,Office office){     
  9.         this.car = car;     
  10.         this.office = office ;     
  11.     }     
  12.       
  13.     …     
  14. }     

  由於 Boss() 構造函數有兩個入參,分別是 car 和 office,@Autowired 將分別尋找和它們類型匹配的 Bean,將它們作為 Boss(Car car ,Office office) 的入參來創建 Boss Bean。  

 

Spring注解:自動注入屬性(@Resource、@Autowired、@Qualifier )

先寫一個場景,舉例說明:

1、接口:IAnimal

public Interface IAnimal{
    ......
}


2、實現類:DogImpl ,實現了IAnimal接口。

@Service("dogImpl")
public class DaoImpl impliments IAnimal{
    ...
}


3、業務類:AnimalController

public class AnimalController {
    @Autowired
    private IAnimal dogImpl;
    ......
}

  假如有一個“動物”的接口 IAnimal, DogImpl類實現了接口 IAnimal, 且該接口只有 DogImpl這一個實現類,那么在引用實現類的時候,我們使用的是實現類的接口(像上面程序展示的那樣)。Spring會按 byType的方式尋找接口的實現類,將其注入。  
  假如有另一個實現類 CatImpl 也實現了接口 IAnimal, 這時候再按上面的方式去引用, 在同時存在兩個實現類的情況下,會出現什么情況呢?

  答:會報錯。 這是由於 @Autowired 的特性決定的: @Autowired 的注入方式是 byType 注入, 當要注入的類型在容器中存在多個時,Spring是不知道要引入哪個實現類的,所以會報錯。

  那么在同一類型擁有多個實現類的時候,如何注入呢?

  答:這種場景下,只能通過 byName 注入的方式。可以使用 @Resource 或 @Qualifier 注解。

       @Resource 默認是按照 byName 的方式注入的, 如果通過 byName 的方式匹配不到,再按 byType 的方式去匹配。所以上面的引用可以替換為:

public class AnimalController {
  @Resource(name="dogImpl") //實現類1中 @Service注解中標定的名稱
  private IAnimal dogImpl;
  ......
}


       @Qualifier 注解也是 byName的方式,但是與@Resource 有區別,@Qualifier 使用的是 類名。

public class AnimalController {
    @Qualifier("DaoImpl") //實現類1的類名。注意區分與@Resource(name="dogImpl") 的區別。
    private IAnimal dogImpl;
    ......
}


總結:
  1、@Autowired 是通過 byType 的方式去注入的, 使用該注解,要求接口只能有一個實現類。
  2、@Resource 可以通過 byName 和 byType的方式注入, 默認先按 byName的方式進行匹配,如果匹配不到,再按 byType的方式進行匹配。
  3、@Qualifier 注解可以按名稱注入, 但是注意是 類名。

 

附:https://www.jianshu.com/p/80df0a6daf65

  https://blog.csdn.net/l1212xiao/article/details/80424064  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM