springMVC @Component-@Resource-@Repository-@Service-@Controller的區(qū)別和理解

作用:

@Component------------------------泛指組件郊尝,當(dāng)組件不好歸類的時候县踢,我們可以使用這個注解進行標(biāo)注怠堪。(Component-------成分; 組分; 零件)

@Resource------------------------(資源)

@Autowired-----------------------(自動綁定)

@Repository-----------------------于標(biāo)注數(shù)據(jù)訪問組件取刃,即DAO組件(repository-------倉庫; 貯藏室闷营,容器烫止。)

@Service----------------------------用于標(biāo)注業(yè)務(wù)層組件(我們通常定義的service層就用這個)

@Controller-------------------------用于標(biāo)注控制層組件(如struts中的action)

這幾個注解的作用相同:都是為實現(xiàn)所在類(即組件)的bean的轉(zhuǎn)化呻疹,然后可以在容器中調(diào)用击狮。然后從名字上的作用就是可以明確各個層次和層次的作用话侧。

首先還是先了解為什么要bean轉(zhuǎn)化栗精。

雖然下面內(nèi)容超多,但是看完真的有不少幫助瞻鹏,若是你不是很了解的話悲立。

spring 2.5 中除了提供 @Component 注釋外,還定義了幾個擁有特殊語義的注釋新博,它們分別是:@Repository薪夕、@Service 和 @Controller。在目前的 Spring 版本中叭披,這 3 個注釋和 @Component 是等效的寥殖,但是從注釋類的命名上玩讳,很容易看出這 3 個注釋分別和持久層、業(yè)務(wù)層和控制層(Web 層)相對應(yīng)嚼贡。雖然目前這 3 個注釋和 @Component 相比沒有什么新意熏纯,但 Spring 將在以后的版本中為它們添加特殊的功能。所以粤策,如果 Web 應(yīng)用程序采用了經(jīng)典的三層分層結(jié)構(gòu)的話樟澜,最好在持久層、業(yè)務(wù)層和控制層分別采用 @Repository叮盘、@Service 和 @Controller 對分層中的類進行注釋秩贰,而用 @Component 對那些比較中立的類進行注釋。

在一個稍大的項目中柔吼,通常會有上百個組件毒费,如果這些組件采用xml的bean定義來配置,顯然會增加配置文件的體積愈魏,查找以及維護起來也不太方便觅玻。 Spring2.5為我們引入了組件自動掃描機制,他可以在類路徑底下尋找標(biāo)注了@Component,@Service,@Controller,@Repository注解的類培漏,并把這些類納入進spring容器中管理溪厘。它的作用和在xml文件中使用bean節(jié)點配置組件時一樣的。要使用自動掃描機制牌柄,我們需要打開以下配置信息:

<?xml version="1.0" encoding="UTF-8" ?> <beansxmlnsbeansxmlns="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-2.5.xsd  http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-2.5.xsd"   
>   
    
<context:component-scan base-package=”com.eric.spring”>     
</beans>    

其中base-package為需要掃描的包(含所有子包) @Service用于標(biāo)注業(yè)務(wù)層組件畸悬,@Controller用于標(biāo)注控制層組件(如struts中的action),@Repository用于標(biāo)注數(shù)據(jù)訪問組件,即DAO組件珊佣,而 @Component泛指組件蹋宦,當(dāng)組件不好歸類的時候,我們可以使用這個注解進行標(biāo)注咒锻。

@Service 
public class VentorServiceImpl implements iVentorService{ } 
@Repository 
public class VentorDaoImpl implements iVentorDao {}

getBean的默認名稱是類名(頭字母小寫)妆档,如果想自定義,可以@Service(“aaaaa”)這樣來指定虫碉,這種bean默認是單例的,如果想改變胸梆,可以使用@Service(“beanName”)@Scope(“prototype”)來改變敦捧。可以使用以下方式指定初始化方法和銷毀方法(方法名任意):

@PostConstruct 
public void init() { } 
@PreDestroy 
public void destory() { }
注入方式:

把DAO實現(xiàn)類注入到service實現(xiàn)類中碰镜,把service的接口(注意不要是service的實現(xiàn)類)注入到action中兢卵,注入時不要new 這個注入的類,因為spring會自動注入绪颖,如果手動再new的話會出現(xiàn)錯誤秽荤,然后屬性加上@Autowired后不需要getter()和setter()方法甜奄,Spring也會自動注入。至于更具體的內(nèi)容窃款,等對注入的方式更加熟練后會做個完整的例子上來课兄。

注解在spring的配置文件里面只需要加上<context:annotation-config/>和<context:component-scanbase-package="需要實現(xiàn)注入的類所在包"/>,可以使用base-package="*"表示全部的類晨继。
< context:component-scan base-package=”com.eric.spring”>
其中base-package為需要掃描的包(含所有子包)

在接口前面標(biāo)上@Autowired和@Qualifier注釋使得接口可以被容器注入烟阐,當(dāng)接口存在兩個實現(xiàn)類的時候必須指定其中一個來注入,使用實現(xiàn)類首字母小寫的字符串來注入紊扬,如:

    @Autowired      
    @Qualifier("chinese")      
     private Man man;

否則可以省略蜒茄,只寫@Autowired 。

Spring中@Autowired注解餐屎、@Resource注解的區(qū)別

Spring不但支持自己定義的@Autowired注解檀葛,還支持幾個由JSR-250規(guī)范定義的注解,它們分別是@Resource腹缩、@PostConstruct以及@PreDestroy屿聋。

@Resource的作用相當(dāng)于@Autowired,只不過@Autowired按byType自動注入庆聘,而@Resource默認按 byName自動注入罷了胜臊。@Resource有兩個屬性是比較重要的,分是name和type伙判,Spring將@Resource注解的name屬性解析為bean的名字象对,而type屬性則解析為bean的類型。所以如果使用name屬性宴抚,則使用byName的自動注入策略勒魔,而使用type屬性時則使用byType自動注入策略。如果既不指定name也不指定type屬性菇曲,這時將通過反射機制使用byName自動注入策略冠绢。

@Resource裝配順序

  1. 如果同時指定了name和type,則從Spring上下文中找到唯一匹配的bean進行裝配常潮,找不到則拋出異常
  2. 如果指定了name弟胀,則從上下文中查找名稱(id)匹配的bean進行裝配,找不到則拋出異常
  3. 如果指定了type喊式,則從上下文中找到類型匹配的唯一bean進行裝配孵户,找不到或者找到多個,都會拋出異常
  4. 如果既沒有指定name岔留,又沒有指定type夏哭,則自動按照byName方式進行裝配;如果沒有匹配献联,則回退為一個原始類型進行匹配竖配,如果匹配則自動裝配何址;

@Autowired 與@Resource的區(qū)別:

1、 @Autowired與@Resource都可以用來裝配bean.都可以寫在字段上,或?qū)懺趕etter方法上进胯。

2用爪、@Autowired默認按類型裝配(這個注解是屬業(yè)spring的),默認情況下必須要求依賴對象必須存在龄减,如果要允許null值项钮,可以設(shè)置它的required屬性為false,如:@Autowired(required=false)希停,如果我們想使用名稱裝配可以結(jié)合@Qualifier注解進行使用烁巫,如下:

a.@Autowired() @Qualifier("baseDao")
b.private BaseDao baseDao;

3、@Resource(這個注解屬于J2EE的)宠能,默認安裝名稱進行裝配亚隙,名稱可以通過name屬性進行指定,如果沒有指定name屬性违崇,當(dāng)注解寫在字段上時阿弃,默認取字段名進行安裝名稱查找,如果注解寫在setter方法上默認取屬性名進行裝配羞延。當(dāng)找不到與名稱匹配的bean時才按照類型進行裝配渣淳。但是需要注意的是,如果name屬性一旦指定伴箩,就只會按照名稱進行裝配入愧。

a.@Resource(name="baseDao")
b.private BaseDao baseDao;

推薦使用:@Resource注解在字段上,這樣就不用寫setter方法了嗤谚,并且這個注解是屬于J2EE的棺蛛,減少了與spring的耦合。這樣代碼看起就比較優(yōu)雅巩步。

使用Spring2.5的新特性——Autowired可以實現(xiàn)快速的自動注入旁赊,而無需在xml文檔里面添加bean的聲明,大大減少了xml文檔的維護(我想到安卓開發(fā)是不是有一個xml里面每個頁面都要在這聲明椅野,類似的原理终畅,原來web開發(fā)也是這么滴,注解出現(xiàn)后竟闪,就不用一個個聲明啦)声离。(偶喜歡這個功能,因為偶對xml不感冒以下是一個例子:

先編寫接口Man:    
        public interface Man {    
            public String sayHello();    
 }    
然后寫Man的實現(xiàn)類Chinese和American:    
       @Service    
public class Chinese implements Man{    
    public String sayHello() {    
        return "I am Chinese!";    
    }    
}    
    
       @Service    
public class American implements Man{    
    public String sayHello() {    
        return "I am American!";    
    }    
}   

@Service注釋表示定義一個bean瘫怜,自動根據(jù)bean的類名實例化一個首寫字母為小寫的bean,例如Chinese實例化為chinese本刽,American實例化為american鲸湃,如果需要自己改名字則:@Service("你自己改的bean名")赠涮。

<?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-2.5.xsd    
           http://www.springframework.org/schema/context    
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">    
      <context:annotation-config/>    
      <context:component-scan base-package="testspring.main"/>    
</beans>  

在spring的配置文件里面只需要加上<context:annotation-config/>和<context:component-scan base-package="需要實現(xiàn)注入的類所在包"/>,可以使用base-package="*"表示全部的類暗挑。

編寫主類測試:    
@Service    
public class Main {    
    @Autowired    
    @Qualifier("chinese")    
    private Man man;    
    public static void main(String[] args) {    
        // TODO code application logic here    
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");    
        Main main = (Main) ctx.getBean("main");    
        System.out.println(main.getMan().sayHello());    
    }    
    public Man getMan() {    
        return man;    
    }    
}  

在Man接口前面標(biāo)上@Autowired和@Qualifier注釋使得Man接口可以被容器注入笋除,當(dāng)Man接口存在兩個實現(xiàn)類的時候必須指定其中一個來注入,使用實現(xiàn)類首字母小寫的字符串來注入炸裆。否則可以省略垃它,只寫@Autowired

注釋配置相對于 XML 配置具有很多的優(yōu)勢:

它可以充分利用 Java 的反射機制獲取類結(jié)構(gòu)信息,這些信息可以有效減少配置的工作烹看。如使用 JPA 注釋配置 ORM 映射時国拇,我們就不需要指定 PO 的屬性名、類型等信息惯殊,如果關(guān)系表字段和 PO 屬性名酱吝、類型都一致,您甚至無需編寫任務(wù)屬性映射信息——因為這些信息都可以通過 Java 反射機制獲取土思。

注釋和 Java 代碼位于一個文件中务热,而 XML 配置采用獨立的配置文件,大多數(shù)配置信息在程序開發(fā)完成后都不會調(diào)整己儒,如果配置信息和 Java 代碼放在一起崎岂,有助于增強程序的內(nèi)聚性。而采用獨立的 XML 配置文件闪湾,程序員在編寫一個功能時冲甘,往往需要在程序文件和配置文件中不停切換,這種思維上的不連貫會降低開發(fā)效率响谓。

因此在很多情況下损合,注釋配置比 XML 配置更受歡迎,注釋配置有進一步流行的趨勢娘纷。Spring 2.5 的一大增強就是引入了很多注釋類嫁审,現(xiàn)在您已經(jīng)可以使用注釋配置完成大部分 XML 配置的功能。在這篇文章里赖晶,我們將向您講述使用注釋進行 Bean 定義和依賴注入的內(nèi)容律适。

原來我們是怎么做的

在使用注釋配置之前,先來回顧一下傳統(tǒng)上是如何配置 Bean 并完成 Bean 之間依賴關(guān)系的建立遏插。下面是 3 個類捂贿,它們分別是 Office、Car 和 Boss胳嘲,這 3 個類需要在 Spring 容器中配置為 Bean:

Office 僅有一個屬性:    
 1. Office.java    
 package com.baobaotao;    
 public class Office {    
     private String officeNo =”001”;     
    //省略 get/setter    
     @Override    
     public String toString() {    
         return "officeNo:" + officeNo;    
     }    
 }    
 Car 擁有兩個屬性:    
2. Car.java    
  package com.baobaotao;    
  public class Car {    
      private String brand;    
      private double price;    
      // 省略 get/setter    
      @Override    
      public String toString() {    
          return "brand:" + brand + "," + "price:" + price;    
      }    
  }    
  Boss 擁有 Office 和 Car 類型的兩個屬性:    
 3. Boss.java    
  package com.baobaotao;    
  public class Boss {    
      private Car car;    
     private Office office;    
       // 省略 get/setter    
       @Override    
      public String toString() {    
         return "car:" + car + "\n" + "office:" + office;    
     }    
  }   

我們在 Spring 容器中將 Office 和 Car 聲明為 Bean厂僧,并注入到 Boss Bean 中:下面是使用傳統(tǒng) XML 完成這個工作的配置文件 beans.xml:

  1. beans.xml 將以上三個類配置成 Bean
<?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-2.5.xsd">    
     <bean id="boss" class="com.baobaotao.Boss">    
         <property name="car" ref="car"/>    
        <property name="office" ref="office" />    
    </bean>    
    <bean id="office" class="com.baobaotao.Office">    
        <property name="officeNo" value="002"/>    
     </bean>    
     <bean id="car" class="com.baobaotao.Car" scope="singleton">    
         <property name="brand" value=" 紅旗 CA72"/>    
        <property name="price" value="2000"/>    
    </bean>    
</beans>    
 當(dāng)我們運行以下代碼時,控制臺將正確打出 boss 的信息: 
  1. 測試類:AnnoIoCTest.java
import org.springframework.context.ApplicationContext;    
  import org.springframework.context.support.ClassPathXmlApplicationContext;    
  public class AnnoIoCTest {    
     public static void main(String[] args) {    
          String[] locations = {"beans.xml"};    
          ApplicationContext ctx =     
             new ClassPathXmlApplicationContext(locations);    
         Boss boss = (Boss) ctx.getBean("boss");    
         System.out.println(boss);    
      }    
  }

使用 @Autowired 注釋
Spring 2.5 引入了 @Autowired 注釋了牛,它可以對類成員變量颜屠、方法及構(gòu)造函數(shù)進行標(biāo)注辰妙,完成自動裝配的工作。來看一下使用 @Autowired 進行成員變量自動注入的代碼:

6. 使用 @Autowired 注釋的 Boss.java    
 package com.baobaotao;    
 import org.springframework.beans.factory.annotation.Autowired;    
 public class Boss {    
    @Autowired    
     private Car car;    
         @Autowired    
     private Office office;    
     …    
 }    
 Spring 通過一個 BeanPostProcessor 對 @Autowired 進行解析甫窟,所以要讓 @Autowired 起作用必須事先在 Spring 容器中聲明 AutowiredAnnotationBeanPostProcessor Bean密浑。    
7. 讓 @Autowired 注釋工作起來    
 <?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-2.5.xsd">    
     <!-- 該 BeanPostProcessor 將自動起作用,對標(biāo)注 @Autowired 的 Bean 進行自動注入 -->    
     <bean class="org.springframework.beans.factory.annotation.    
         AutowiredAnnotationBeanPostProcessor"/>    
    
    <!-- 移除 boss Bean 的屬性注入配置的信息 -->    
    <bean id="boss" class="com.baobaotao.Boss"/>    
       <bean id="office" class="com.baobaotao.Office">    
         <property name="officeNo" value="001"/>    
     </bean>    
     <bean id="car" class="com.baobaotao.Car" scope="singleton">    
         <property name="brand" value=" 紅旗 CA72"/>    
       <property name="price" value="2000"/>    
    </bean>    
 </beans>   

這樣粗井,當(dāng) Spring 容器啟動時尔破,AutowiredAnnotationBeanPostProcessor 將掃描 Spring 容器中所有 Bean,當(dāng)發(fā)現(xiàn) Bean 中擁有 @Autowired
注釋時就找到和其匹配(默認按類型匹配)的 Bean浇衬,并注入到對應(yīng)的地方中去懒构。

按照上面的配置,Spring 將直接采用 Java 反射機制對 Boss 中的 car 和 office 這兩個私有成員變量進行自動注入径玖。所以對成員變量使用 @Autowired 后痴脾,您大可將它們的 setter 方法(setCar() 和 setOffice())從 Boss 中刪除。

當(dāng)然梳星,您也可以通過 @Autowired 對方法或構(gòu)造函數(shù)進行標(biāo)注赞赖,來看下面的代碼:

8. 將 @Autowired 注釋標(biāo)注在 Setter 方法上    
 package com.baobaotao;    
 public class Boss {    
     private Car car;    
     private Office office;    
     
      @Autowired    
    public void setCar(Car car) {    
        this.car = car;    
    }    
  
    @Autowired    
     public void setOffice(Office office) {    
         this.office = office;    
    }    
     …    
 }    
 這時,@Autowired 將查找被標(biāo)注的方法的入?yún)㈩愋偷?Bean冤灾,并調(diào)用方法自動注入這些 Bean前域。而下面的使用方法則對構(gòu)造函數(shù)進行標(biāo)注:    
9. 將 @Autowired 注釋標(biāo)注在構(gòu)造函數(shù)上    
 package com.baobaotao;    
 public class Boss {    
     private Car car;    
     private Office office;    
  
     @Autowired    
     public Boss(Car car ,Office office){    
         this.car = car;    
        this.office = office ;    
    }    
    …    
}    
 由于 Boss() 構(gòu)造函數(shù)有兩個入?yún)ⅲ謩e是 car 和 office韵吨,@Autowired 將分別尋找和它們類型匹配的 Bean匿垄,將它們作為 Boss(Car car ,Office office) 的入?yún)韯?chuàng)建 Boss Bean。  

當(dāng)候選 Bean 數(shù)目不為 1 時的應(yīng)對方法

在默認情況下使用 @Autowired 注釋進行自動注入時归粉,Spring 容器中匹配的候選 Bean 數(shù)目必須有且僅有一個椿疗。當(dāng)找不到一個匹配的 Bean 時,Spring 容器將拋出 BeanCreationException 異常糠悼,并指出必須至少擁有一個匹配的 Bean届榄。我們可以來做一個實驗:

10. 候選 Bean 數(shù)目為 0 時    
 <?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-2.5.xsd ">    
      
    <bean class="org.springframework.beans.factory.annotation.    
         AutowiredAnnotationBeanPostProcessor"/>     
       <bean id="boss" class="com.baobaotao.Boss"/>    
     
    <!-- 將 office Bean 注釋掉 -->    
    <!-- <bean id="office" class="com.baobaotao.Office">    
     <property name="officeNo" value="001"/>    
    </bean>-->    
    
     <bean id="car" class="com.baobaotao.Car" scope="singleton">    
        <property name="brand" value=" 紅旗 CA72"/>    
         <property name="price" value="2000"/>    
    </bean>    
 </beans>   

由于 office Bean 被注釋掉了,所以 Spring 容器中將沒有類型為 Office 的 Bean 了倔喂,而 Boss 的 office 屬性標(biāo)注了 @Autowired铝条,當(dāng)啟動 Spring 容器時,異常就產(chǎn)生了席噩。

當(dāng)不能確定 Spring 容器中一定擁有某個類的 Bean 時班缰,可以在需要自動注入該類 Bean 的地方可以使用 @Autowired(required = false),這等于告訴 Spring:在找不到匹配 Bean 時也不報錯悼枢。來看一下具體的例子:

11. 使用 @Autowired(required = false)    
package com.baobaotao;    
import org.springframework.beans.factory.annotation.Autowired;    
import org.springframework.beans.factory.annotation.Required;    
 public class Boss {    
     private Car car;    
    private Office office;    
     @Autowired    
     public void setCar(Car car) {    
         this.car = car;    
     }    
    @Autowired(required = false)    
     public void setOffice(Office office) {    
        this.office = office;    
    }    
    …    
 }    
當(dāng)然埠忘,一般情況下,使用 @Autowired 的地方都是需要注入 Bean 的,使用了自動注入而又允許不注入的情況一般僅會在開發(fā)期或測試期碰到(如為了快速啟動 Spring 容器莹妒,僅引入一些模塊的 Spring 配置文件)假丧,所以 @Autowired(required = false) 會很少用到。

和找不到一個類型匹配 Bean 相反的一個錯誤是:如果 Spring 容器中擁有多個候選 Bean动羽,Spring 容器在啟動時也會拋出 BeanCreationException 異常。來看下面的例子:

12. 在 beans.xml 中配置兩個 Office 類型的 Bean    
 <bean id="office" class="com.baobaotao.Office">    
    <property name="officeNo" value="001"/>    
 </bean>    
 <bean id="office2" class="com.baobaotao.Office">    
     <property name="officeNo" value="001"/>    
 </bean>    
 …    
 我們在 Spring 容器中配置了兩個類型為 Office 類型的 Bean渔期,當(dāng)對 Boss 的 office 成員變量進行自動注入時运吓,Spring 容器將無法確定到底要用哪一個 Bean,因此異常發(fā)生了疯趟。    
 Spring 允許我們通過 @Qualifier 注釋指定注入 Bean 的名稱拘哨,這樣歧義就消除了,可以通過下面的方法解決異常:    
13. 使用 @Qualifier 注釋指定注入 Bean 的名稱    
@Autowired    
 public void setOffice(@Qualifier("office")Office office) {    
     this.office = office;    
 }    
 @Qualifier("office") 中的 office 是 Bean 的名稱信峻,所以 @Autowired 和 @Qualifier 結(jié)合使用時倦青,自動注入的策略就從 byType 轉(zhuǎn)變成 byName 了。@Autowired 可以對成員變量盹舞、方法以及構(gòu)造函數(shù)進行注釋产镐,而 @Qualifier 的標(biāo)注對象是成員變量、方法入?yún)⑻卟健?gòu)造函數(shù)入?yún)⒀⒀恰U怯捎谧⑨寣ο蟮牟煌?Spring 不將 @Autowired 和 @Qualifier 統(tǒng)一成一個注釋類获印。下面是對成員變量和構(gòu)造函數(shù)入?yún)⑦M行注釋的代碼:    
 //對成員變量進行注釋:    
14. 對成員變量使用 @Qualifier 注釋    
public class Boss {    
     @Autowired    
     private Car car;    
    @Autowired    
    @Qualifier("office")    
   private Office office;    
    …    
}    
 //對構(gòu)造函數(shù)入?yún)⑦M行注釋:    
15. 對構(gòu)造函數(shù)變量使用 @Qualifier 注釋    
 public class Boss {    
     private Car car;    
     private Office office;    
  
     @Autowired    
     public Boss(Car car , @Qualifier("office")Office office){    
         this.car = car;    
         this.office = office ;    
     }    
 }    
 @Qualifier 只能和 @Autowired 結(jié)合使用述雾,是對 @Autowired 有益的補充。一般來講兼丰,@Qualifier 對方法簽名中入?yún)⑦M行注釋會降低代碼的可讀性玻孟,而對成員變量注釋則相對好一些。  

使用 JSR-250 的注釋
Spring 不但支持自己定義的 @Autowired 的注釋鳍征,還支持幾個由 JSR-250 規(guī)范定義的注釋黍翎,它們分別是 @Resource、@PostConstruct 以及 @PreDestroy蟆技。
@Resource
@Resource 的作用相當(dāng)于 @Autowired玩敏,只不過 @Autowired 按 byType 自動注入,面 @Resource 默認按 byName 自動注入罷了质礼。@Resource 有兩個屬性是比較重要的旺聚,分別是 name 和 type,Spring 將 @Resource 注釋的 name 屬性解析為 Bean 的名字眶蕉,而 type 屬性則解析為 Bean 的類型砰粹。所以如果使用 name 屬性,則使用 byName 的自動注入策略,而使用 type 屬性時則使用 byType 自動注入策略碱璃。如果既不指定 name 也不指定 type 屬性弄痹,這時將通過反射機制使用 byName 自動注入策略。

Resource 注釋類位于 Spring 發(fā)布包的 lib/j2ee/common-annotations.jar 類包中嵌器,因此在使用之前必須將其加入到項目的類庫中肛真。來看一個使用 @Resource 的例子:

16. 使用 @Resource 注釋的 Boss.java    
 package com.baobaotao;    
 import javax.annotation.Resource;    
 public class Boss {    
     // 自動注入類型為 Car 的 Bean    
    @Resource    
     private Car car;    
     
     // 自動注入 bean 名稱為 office 的 Bean    
     @Resource(name = "office")    
    private Office office;    
 }    
 一般情況下,我們無需使用類似于 @Resource(type=Car.class) 的注釋方式爽航,因為 Bean 的類型信息可以通過 Java 反射從代碼中獲取蚓让。    
 要讓 JSR-250 的注釋生效,除了在 Bean 類中標(biāo)注這些注釋外讥珍,還需要在 Spring 容器中注冊一個負責(zé)處理這些注釋的 BeanPostProcessor:    
 <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>    
 CommonAnnotationBeanPostProcessor 實現(xiàn)了 BeanPostProcessor 接口历极,它負責(zé)掃描使用了 JSR-250 注釋的 Bean,并對它們進行相應(yīng)的操作衷佃。

@PostConstruct 和 @PreDestroy

Spring 容器中的 Bean 是有生命周期的趟卸,Spring 允許在 Bean 在初始化完成后以及 Bean 銷毀前執(zhí)行特定的操作,您既可以通過實現(xiàn) InitializingBean/DisposableBean 接口來定制初始化之后 / 銷毀之前的操作方法氏义,也可以通過 <bean> 元素的 init-method/destroy-method 屬性指定初始化之后 / 銷毀之前調(diào)用的操作方法锄列。關(guān)于 Spring 的生命周期,筆者在《精通 Spring 2.x—企業(yè)應(yīng)用開發(fā)精解》第 3 章進行了詳細的描述觅赊,有興趣的讀者可以查閱右蕊。

JSR-250 為初始化之后/銷毀之前方法的指定定義了兩個注釋類,分別是 @PostConstruct 和 @PreDestroy吮螺,這兩個注釋只能應(yīng)用于方法上饶囚。標(biāo)注了 @PostConstruct 注釋的方法將在類實例化后調(diào)用,而標(biāo)注了 @PreDestroy 的方法將在類銷毀之前調(diào)用鸠补。

17. 使用 @PostConstruct 和 @PreDestroy 注釋的 Boss.java    
 package com.baobaotao;    
 import javax.annotation.Resource;    
 import javax.annotation.PostConstruct;    
 import javax.annotation.PreDestroy;    
 public class Boss {    
     @Resource    
     private Car car;    
    @Resource(name = "office")    
     private Office office;    
    @PostConstruct    
    public void postConstruct1(){    
       System.out.println("postConstruct1");    
    }    
     @PreDestroy    
    public void preDestroy1(){    
       System.out.println("preDestroy1");     
  }    
    …    
 }    
 您只需要在方法前標(biāo)注 @PostConstruct 或 @PreDestroy萝风,這些方法就會在 Bean 初始化后或銷毀之前被 Spring 容器執(zhí)行了。    
 我們知道紫岩,不管是通過實現(xiàn) InitializingBean/DisposableBean 接口规惰,還是通過 <bean> 元素的 init-method/destroy-method 屬性進行配置,都只能為 Bean 指定一個初始化 / 銷毀的方法泉蝌。但是使用 @PostConstruct 和 @PreDestroy 注釋卻可以指定多個初始化 / 銷毀方法歇万,那些被標(biāo)注 @PostConstruct 或 @PreDestroy 注釋的方法都會在初始化 / 銷毀時被執(zhí)行。    
 通過以下的測試代碼勋陪,您將可以看到 Bean 的初始化 / 銷毀方法是如何被執(zhí)行的:    
18. 測試類代碼    
 package com.baobaotao;    
 import org.springframework.context.support.ClassPathXmlApplicationContext;    
 public class AnnoIoCTest {    
    public static void main(String[] args) {    
         String[] locations = {"beans.xml"};    
        ClassPathXmlApplicationContext ctx =     
           new ClassPathXmlApplicationContext(locations);    
         Boss boss = (Boss) ctx.getBean("boss");    
        System.out.println(boss);    
        ctx.destroy();// 關(guān)閉 Spring 容器贪磺,以觸發(fā) Bean 銷毀方法的執(zhí)行    
    }    
 }    
 這時,您將看到標(biāo)注了 @PostConstruct 的 postConstruct1() 方法將在 Spring 容器啟動時诅愚,創(chuàng)建 Boss Bean 的時候被觸發(fā)執(zhí)行寒锚,而標(biāo)注了 @PreDestroy 注釋的 preDestroy1() 方法將在 Spring 容器關(guān)閉前銷毀 Boss Bean 的時候被觸發(fā)執(zhí)行。    
 使用 <context:annotation-config/> 簡化配置    
 Spring 2.1 添加了一個新的 context 的 Schema 命名空間,該命名空間對注釋驅(qū)動刹前、屬性文件引入泳赋、加載期織入等功能提供了便捷的配置。我們知道注釋本身是不會做任何事情的喇喉,它僅提供元數(shù)據(jù)信息祖今。要使元數(shù)據(jù)信息真正起作用,必須讓負責(zé)處理這些元數(shù)據(jù)的處理器工作起來拣技。     
而我們前面所介紹的 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 就是處理這些注釋元數(shù)據(jù)的處理器衅鹿。但是直接在 Spring 配置文件中定義這些 Bean 顯得比較笨拙。Spring 為我們提供了一種方便的注冊這些 BeanPostProcessor 的方式过咬,這就是 <context:annotation-config/>。請看下面的配置:    
19. 調(diào)整 beans.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-2.5.xsd    
  http://www.springframework.org/schema/context     
  http://www.springframework.org/schema/context/spring-context-2.5.xsd">    
     <context:annotation-config/>     
     <bean id="boss" class="com.baobaotao.Boss"/>    
     <bean id="office" class="com.baobaotao.Office">    
        <property name="officeNo" value="001"/>    
     </bean>    
    <bean id="car" class="com.baobaotao.Car" scope="singleton">    
        <property name="brand" value=" 紅旗 CA72"/>    
        <property name="price" value="2000"/>    
    </bean>    
 </beans>    
 <context:annotationconfig/> 將隱式地向 Spring 容器注冊 AutowiredAnnotationBeanPostProcessor制妄、CommonAnnotationBeanPostProcessor掸绞、PersistenceAnnotationBeanPostProcessor 以及 equiredAnnotationBeanPostProcessor 這 4 個 BeanPostProcessor。    
 在配置文件中使用 context 命名空間之前耕捞,必須在 <beans> 元素中聲明 context 命名空間衔掸。    
 使用 @Component    
 雖然我們可以通過 @Autowired 或 @Resource 在 Bean 類中使用自動注入功能,但是 Bean 還是在 XML 文件中通過 <bean> 進行定義 —— 也就是說俺抽,在 XML 配置文件中定義 Bean敞映,通過 @Autowired 或 @Resource 為 Bean 的成員變量、方法入?yún)⒒驑?gòu)造函數(shù)入?yún)⑻峁┳詣幼⑷氲墓δ芰赘D芊褚餐ㄟ^注釋定義 Bean振愿,從 XML 配置文件中完全移除 Bean 定義的配置呢?答案是肯定的弛饭,我們通過 Spring 2.5 提供的 @Component 注釋就可以達到這個目標(biāo)了冕末。    
 下面,我們完全使用注釋定義 Bean 并完成 Bean 之間裝配:    
20. 使用 @Component 注釋的 Car.java    
 package com.baobaotao;    
 import org.springframework.stereotype.Component;    
 @Component    
 public class Car {    
     …    
 }       
 僅需要在類定義處侣颂,使用 @Component 注釋就可以將一個類定義了 Spring 容器中的 Bean档桃。下面的代碼將 Office 定義為一個 Bean:    
21. 使用 @Component 注釋的 Office.java    
 package com.baobaotao;    
 import org.springframework.stereotype.Component;    
 @Component    
 public class Office {    
     private String officeNo = "001";    
     …    
 }    
 這樣,我們就可以在 Boss 類中通過 @Autowired 注入前面定義的 Car 和 Office Bean 了憔晒。    
22. 使用 @Component 注釋的 Boss.java    
 package com.baobaotao;    
 import org.springframework.beans.factory.annotation.Autowired;    
 import org.springframework.beans.factory.annotation.Required;    
 import org.springframework.beans.factory.annotation.Qualifier;    
 import org.springframework.stereotype.Component;      
 @Component("boss")    
 public class Boss {    
    @Autowired    
    private Car car;    
     @Autowired    
     private Office office;    
     …    
 }    
 @Component 有一個可選的入?yún)⒃逡蓿糜谥付?Bean 的名稱,在 Boss 中拒担,我們就將 Bean 名稱定義為“boss”嘹屯。一般情況下,Bean 都是 singleton 的澎蛛,需要注入 Bean 的地方僅需要通過 byType 策略就可以自動注入了抚垄,所以大可不必指定 Bean 的名稱。    
 在使用 @Component 注釋后,Spring 容器必須啟用類掃描機制以啟用注釋驅(qū)動 Bean 定義和注釋驅(qū)動 Bean 自動注入的策略呆馁。Spring 2.5 對 context 命名空間進行了擴展桐经,提供了這一功能,請看下面的配置:    
23. 簡化版的 beans.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-2.5.xsd    
  http://www.springframework.org/schema/context     
  http://www.springframework.org/schema/context/spring-context-2.5.xsd">    
     <context:component-scan base-package="com.baobaotao"/>    
 </beans>    
 這里浙滤,所有通過 <bean> 元素定義 Bean 的配置內(nèi)容已經(jīng)被移除阴挣,僅需要添加一行 <context:component-scan/> 配置就解決所有問題了——Spring XML 配置文件得到了極致的簡化(當(dāng)然配置元數(shù)據(jù)還是需要的,只不過以注釋形式存在罷了)纺腊。<context:component-scan/> 的 base-package 屬性指定了需要掃描的類包畔咧,類包及其遞歸子包中所有的類都會被處理。    
 <context:component-scan/> 還允許定義過濾器將基包下的某些類納入或排除揖膜。Spring 支持以下 4 種類型的過濾方式誓沸,通過下表說明:    
 表 1. 掃描過濾方式    
 過濾器類型 說明     
 注釋 假如 com.baobaotao.SomeAnnotation 是一個注釋類,我們可以將使用該注釋的類過濾出來壹粟。     
 類名指定 通過全限定類名進行過濾拜隧,如您可以指定將 com.baobaotao.Boss 納入掃描,而將 com.baobaotao.Car 排除在外趁仙。     
 正則表達式 通過正則表達式定義過濾的類洪添,如下所示: com\.baobaotao\.Default.*     
 AspectJ 表達式 通過 AspectJ 表達式定義過濾的類,如下所示: com. baobaotao..*Service+     
 下面是一個簡單的例子:     
 <context:component-scan base-package="com.baobaotao">    
     <context:include-filter type="regex"     
         expression="com\.baobaotao\.service\..*"/>    
     <context:exclude-filter type="aspectj"     
         expression="com.baobaotao.util..*"/>    
 </context:component-scan>    
 值得注意的是 <context:component-scan/> 配置項不但啟用了對類包進行掃描以實施注釋驅(qū)動 Bean 定義的功能雀费,同時還啟用了注釋驅(qū)動自動注入的功能(即還隱式地在內(nèi)部注冊了 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor)干奢,因此當(dāng)使用 <context:component-scan/> 后,就可以將 <context:annotation-config/> 移除了盏袄。    
 默認情況下通過 @Component 定義的 Bean 都是 singleton 的忿峻,如果需要使用其它作用范圍的 Bean,可以通過 @Scope 注釋來達到目標(biāo)辕羽,如以下代碼所示:    
24. 通過 @Scope 指定 Bean 的作用范圍    
 package com.baobaotao;    
 import org.springframework.context.annotation.Scope;    
 …    
 @Scope("prototype")    
 @Component("boss")    
 public class Boss {    
     …    
 }    

這樣炭菌,當(dāng)從 Spring 容器中獲取 boss Bean 時,每次返回的都是新的實例了逛漫。

注釋配置和 XML 配置的適用場合

是否有了這些 IOC 注釋黑低,我們就可以完全摒除原來 XML 配置的方式呢?答案是否定的酌毡。有以下幾點原因:
注釋配置不一定在先天上優(yōu)于 XML 配置克握。如果 Bean 的依賴關(guān)系是固定的,(如 Service 使用了哪幾個 DAO 類)枷踏,這種配置信息不會在部署時發(fā)生調(diào)整菩暗,那么注釋配置優(yōu)于 XML 配置;反之如果這種依賴關(guān)系會在部署時發(fā)生調(diào)整旭蠕,XML 配置顯然又優(yōu)于注釋配置停团,因為注釋是對 Java 源代碼的調(diào)整旷坦,您需要重新改寫源代碼并重新編譯才可以實施調(diào)整。
如果 Bean 不是自己編寫的類(如 JdbcTemplate佑稠、SessionFactoryBean 等)秒梅,注釋配置將無法實施,此時 XML 配置是唯一可用的方式舌胶。
注釋配置往往是類級別的捆蜀,而 XML 配置則可以表現(xiàn)得更加靈活。比如相比于 @Transaction 事務(wù)注釋幔嫂,使用 aop/tx 命名空間的事務(wù)配置更加靈活和簡單辆它。
所以在實現(xiàn)應(yīng)用中,我們往往需要同時使用注釋配置和 XML 配置履恩,對于類級別且不會發(fā)生變動的配置可以優(yōu)先考慮注釋配置锰茉;而對于那些第三方類以及容易發(fā)生調(diào)整的配置則應(yīng)優(yōu)先考慮使用 XML 配置。Spring 會在具體實施 Bean 創(chuàng)建和 Bean 注入之前將這兩種配置方式的元信息融合在一起切心。

小結(jié)

Spring 在 2.1 以后對注釋配置提供了強力的支持洞辣,注釋配置功能成為 Spring 2.5 的最大的亮點之一。合理地使用 Spring 2.5 的注釋配置昙衅,可以有效減少配置的工作量,提高程序的內(nèi)聚性定鸟。但是這并不意味著傳統(tǒng) XML 配置將走向消亡而涉,在第三方類 Bean 的配置,以及那些諸如數(shù)據(jù)源联予、緩存池啼县、持久層操作模板類、事務(wù)管理等內(nèi)容的配置上沸久,XML 配置依然擁有不可替代的地位季眷。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市卷胯,隨后出現(xiàn)的幾起案子子刮,更是在濱河造成了極大的恐慌,老刑警劉巖窑睁,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挺峡,死亡現(xiàn)場離奇詭異,居然都是意外死亡担钮,警方通過查閱死者的電腦和手機橱赠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來箫津,“玉大人狭姨,你說我怎么就攤上這事宰啦。” “怎么了饼拍?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵赡模,是天一觀的道長。 經(jīng)常有香客問我惕耕,道長纺裁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任司澎,我火速辦了婚禮欺缘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挤安。我一直安慰自己谚殊,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布蛤铜。 她就那樣靜靜地躺著嫩絮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪围肥。 梳的紋絲不亂的頭發(fā)上剿干,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天,我揣著相機與錄音穆刻,去河邊找鬼置尔。 笑死,一個胖子當(dāng)著我的面吹牛氢伟,可吹牛的內(nèi)容都是我干的榜轿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼朵锣,長吁一口氣:“原來是場噩夢啊……” “哼谬盐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起诚些,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤飞傀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后诬烹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體助析,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年椅您,在試婚紗的時候發(fā)現(xiàn)自己被綠了外冀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡掀泳,死狀恐怖雪隧,靈堂內(nèi)的尸體忽然破棺而出西轩,到底是詐尸還是另有隱情,我是刑警寧澤脑沿,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布藕畔,位于F島的核電站,受9級特大地震影響庄拇,放射性物質(zhì)發(fā)生泄漏注服。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一措近、第九天 我趴在偏房一處隱蔽的房頂上張望溶弟。 院中可真熱鬧,春花似錦瞭郑、人聲如沸辜御。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽擒权。三九已至,卻和暖如春阁谆,著一層夾襖步出監(jiān)牢的瞬間碳抄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工场绿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留剖效,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓裳凸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親劝贸。 傳聞我的和親對象是個殘疾皇子姨谷,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)映九,斷路器梦湘,智...
    卡卡羅2017閱讀 134,672評論 18 139
  • 1.1 spring IoC容器和beans的簡介 Spring 框架的最核心基礎(chǔ)的功能是IoC(控制反轉(zhuǎn))容器,...
    simoscode閱讀 6,719評論 2 22
  • 1.1 Spring IoC容器和bean簡介 本章介紹了Spring Framework實現(xiàn)的控制反轉(zhuǎn)(IoC)...
    起名真是難閱讀 2,584評論 0 8
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,827評論 6 342
  • 平生未止二十二件甥,丹青畫彩繪無疆捌议。 不染錢名功與利,胸懷大志盼國強引有。 凜然剛毅比靈均瓣颅,不避死生如少穆。 瞭看風(fēng)光數(shù)萬...
    魚筱悅閱讀 199評論 0 0