@Autowired桶略、@Resource语淘、@Inject和@Service

一、區(qū)別總結

1??

  1. @Autowired 是 Spring 自帶的删性,通過AutowiredAnnotationBeanPostProcessor類實現(xiàn)的依賴注入亏娜,Spring 屬于第三方的。
  2. @Resource 是 JSR250 規(guī)范的實現(xiàn)蹬挺,J2EE 的注解维贺,在javax.annotation包下。J2EE 是 Java 自己的巴帮,建議使用 @Resource 注解溯泣,以減少代碼和 Spring 之間的耦合。
  3. @Inject 是 JSR330 規(guī)范實現(xiàn)的榕茧,需要導入javax.inject.Inject jar包垃沦,才能實現(xiàn)注入。

2??

  1. @Autowired 可以作用在 constructor用押、method肢簿、parameter、annotation_type蜻拨、field 上池充。
  2. @Resource 可以作用 method、field缎讼、type 上收夸。
  3. @Inject 可以作用 constructor、method血崭、field 上卧惜。

3??

  1. @Autowired 默認按照(byType)進行 bean 匹配。如果有多個類型一樣的 bean 候選者夹纫,需要配合 @Qualifier 按照(byName)進行裝配咽瓷。指定名稱后,如果 Spring IOC 容器中沒有對應的組件 bean 拋出 NoSuchBeanDefinitionException舰讹。也可以將該注解屬性 required 配置為 false忱详,找不到相應 bean 的時候,系統(tǒng)不再拋異常跺涤。

  2. ①@Resource 默認按照(byName)方式進行自動裝配匈睁,找不到再按 type 去匹配监透。如果有多個類型一樣的 bean 候選者,則可以通過 name 屬性指定進行注入航唆。
    ②指定了 name 或者 type 則根據(jù)指定的類型去匹配 bean胀蛮。
    ③指定了 name 和 type 則根據(jù)指定的 name 和 type 去匹配 bean,任何一個不匹配都會報錯糯钙。

  3. @Inject 是根據(jù)類型進行自動裝配的粪狼,如果需要按名稱進行裝配,則需要配合 @Named任岸。

4??@Autowired再榄、@Inject 用法基本一樣。不同的是 @Autowired 有一個 request 屬性享潜。

二困鸥、什么是注解

Annotation(注解)是 JDK1.5 及以后版本引入的。它可以用于創(chuàng)建文檔剑按,跟蹤代碼中的依賴性疾就,甚至執(zhí)行基本編譯時檢查。注解是以@注解名在代碼中存在的艺蝴。根據(jù)注解參數(shù)的個數(shù)猬腰,可以將注解分為:標記注解、單值注解猜敢、完整注解三類姑荷。它們都不會直接影響到程序的語義,只是作為注解(標識)存在缩擂,可以通過反射機制編程實現(xiàn)對這些元數(shù)據(jù)(用來描述數(shù)據(jù)的數(shù)據(jù))的訪問鼠冕。另外,可以在編譯時選擇代碼里的注解是否只存在于源代碼級撇叁,或者它也能在 class 文件、或者運行時中出現(xiàn)(SOURCE/CLASS/RUNTIME)畦贸。

  • @Component:通用的注解陨闹,可標注任意類為 Spring 組件。如果一個 bean 不知道屬于哪個層薄坏,可以使用 @Component 注解標注趋厉。
  • @Repository:對應持久層即 Dao 層,主要用于數(shù)據(jù)庫相關操作胶坠。
  • @Service:對應服務層君账,主要涉及一些復雜的邏輯,需要用到 Dao 層沈善。
  • @Controller:對應 Spring MVC 控制層乡数,主要用于接受用戶請求并調用 Service 層返回數(shù)據(jù)給前端頁面椭蹄。

三、注解的效應

傳統(tǒng)的 Spring 做法是使用 .xml 文件來對 bean 進行注入或者是配置 AOP净赴、事務绳矩,這么做有兩個缺點:

  1. 如果所有的內容都配置在 .xml 文件中,會導致 .xml 文件過大玖翅;如果按需求分開 .xml 文件翼馆,又會導致 .xml 文件過多〗鸲龋總之這會使得配置文件的可讀性與可維護性變得很低应媚。
  2. 開發(fā)中,在 .java 文件和 .xml 文件之間不斷切換猜极,是一件麻煩的事中姜。同時這種思維上的不連貫也會降低開發(fā)的效率。

為了解決這兩個問題魔吐,Spring 引入了注解扎筒,通過@注解名的方式,讓注解與 Java Bean 緊密結合酬姆,既大大減少了配置文件的體積嗜桌,又增加了 Java Bean 的可讀性與內聚性。

四辞色、@Autowired骨宠、@Resource、@Inject 和 @Service

1??看一個不使用注解的 Spring 示例相满,在這個示例的基礎上层亿,改成注解版本的,這樣也能看出使用與不使用注解之間的區(qū)別立美,先定義一個老師:

public class Teacher{
 private String teacherName = "TW";
 public String toString() {
    return "TeacherName:" + teacherName;
 }
}

再定義一個學生:

public class Student{
 private String studentName = "SL";
 public String toString() {
  return "StudentName:" + studentName;
 }
}

然后定義一個學校:

public class School{
 private Teacher teacher;
 private Student student;
 public void setTeacher(Teacher teacher){
  this.teacher = teacher;
 }
 public void setStudent(Student student){
  this.student = student;
 }
 public Teacher getTeacher(){
  return teacher;
 }
 public Student getStudent(){
  return student;
 }
 public String toString(){
  return teacher + "\n" + student;
 }
}

Spring的配置文件這么寫:

<?xml version="1.0" encoding="UTF-8"?>
<bean id="school" class="com.wg.bean.School" >
    <property name="teacher" ref="teacher" />
    <property name="student" ref="student" />
</bean>
<bean id="teacher" class="com.wg.uu.Teacher" />
<bean id="student" class="com.wg.uu.Student" />

這是最初始的 .xml 配置匿又。

2??@Autowired

自動裝配。其作用是替代 Java 代碼里面的 getter/setter 與 bean 屬性中的 property建蹄。如果私有屬性需要對外提供的話碌更,getter 應當予以保留。引入 @Autowired 注解洞慎,先看一下 Spring 配置文件怎么寫:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
 3     xmlns="http://www.springframework.org/schema/beans"  
 4     xmlns:context="http://www.springframework.org/schema/context"  
 5     xsi:schemaLocation="http://www.springframework.org/schema/beans 
 6         http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
 7         http://www.springframework.org/schema/context
 8         http://www.springframework.org/schema/context/spring-context-4.2.xsd">
 9     
10     <context:component-scan base-package="com.wg" />
11     
12     <bean id="school"  class="com.wg.bean.School" />
13     <bean id="teacher" class="com.wg.uu.Teacher" />
14     <bean id="student" class="com.wg.uu.Student" />
15     
16 </beans>

注意第10行痛单,為了實現(xiàn) bean 的自動載入,必須配置 Spring 的掃描器劲腿。在 base-package 指明一個包:

<context:component-scan base-package=“com.wg”/>

表明com.wg包及其子包中旭绒,如果某個類的頭上帶有特定的注解@Component@Repository@Service@Controller挥吵,就會將這個對象作為 Bean 注入進 Spring 容器重父。有了context:component-scan,另一個context:annotation-config標簽就可以移除掉蔫劣,因為已經(jīng)被包含進去了坪郭。
context:component-scan提供兩個子標簽:context:include-filtercontext:exclude-filter。各代表引入和排除的過濾脉幢。

看到第12行歪沃,原來 school 里面應當注入兩個屬性 teacher、student嫌松,現(xiàn)在不需要注入了沪曙。再看下,School.java 也很簡練萎羔,getter/setter 都可以去掉:

public class School{
 @Autowired
 private Teacher teacher;
 @Autowired
 private Student student;
 public String toString(){
  return teacher + "\n" + student;
 }
}

這里@Autowired注解的意思就是液走,當 Spring 發(fā)現(xiàn)@Autowired注解時,將自動在代碼上下文中找到與其匹配(默認是類型匹配)的Bean贾陷,并自動注入到相應的地方去。

xml優(yōu)先原則
值得注意的是髓废,假如 .xml 文件 bean 里面有 property巷懈,而 School.java 里面卻去掉了屬性的 getter/setter,并使用@Autowired注解標注這兩個屬性會怎么樣慌洪?答案是 Spring 會按照 xml 優(yōu)先的原則去 School.java 中尋找這兩個屬性的 getter/setter顶燕,導致的結果就是初始化 bean 報錯。

再假如此時把 .xml 文件的13行冈爹、14行兩行再給去掉涌攻,運行會拋出異常:
Exception in thread “main” org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘School’: Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.zxt.uu.Teacher com.zxt.bean.School.teacher; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.wg.uu.Teacher] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) …
因為,@Autowired注解要去尋找的是一個 Bean频伤,Teacher 和 Student 的 Bean 定義都給去掉了恳谎,自然就不是一個 Bean 了,Spring 容器找不到也很好理解憋肖。那么因痛,如果屬性找不到又不想讓 Spring 容器拋出異常,而就是顯示 null瞬哼,可以嗎婚肆?可以租副,其實異常信息里面也給出了提示坐慰,就是將@Autowired注解的 required 屬性設置為 false 即可:

public class School{
 @Autowired(required = false)
 private Teacher teacher;
 @Autowired(required = false)
 private Student student;
 public String toString(){
  return teacher + "\n" + student;
 }
}

此時,找不到 teacher、student 兩個屬性结胀,Spring 容器不再拋出異常而是認為這兩個屬性為 null赞咙。

@Autowired接口注入----->@Qualifier

上面僅僅只是注入一個 Java 類,比較簡單糟港。那么如果有一個接口攀操,有多個實現(xiàn),Bean 里引用的是接口名秸抚,又該如何速和?比如有一個 Person 接口:

public interface Person{
 public String personName();
}

兩個實現(xiàn)類 Doctor 和 Police:

@Service
public class Doctor implements Person{
 public String docName(){
  return "Doctor person";
 }
}
@Service
public class Police implements Person{
 public String personName(){
  return "Police person";
 }
}

寫一個 PersonFactory,引用 Person:

@Service
public class PersonFactory{
 @Autowired
 private Person person;
 public String toString(){
  return person.personName();
 }
}

Person 接口有兩個實現(xiàn)類剥汤,Spring 并不知道應當引用哪個實現(xiàn)類颠放,代碼報錯。這種情況通常有兩個解決辦法:

  1. 刪除其中一個實現(xiàn)類吭敢,Spring 會自動去 base-package 下尋找 Person 接口的實現(xiàn)類碰凶,發(fā)現(xiàn) Person 接口只有一個實現(xiàn)類,便會直接引用這個實現(xiàn)類鹿驼。
  2. 實現(xiàn)類就是有多個該怎么辦欲低?此時可以使用 @Qualifier 注解:
@Service
public class PersonFactory{
 @Autowired
 @Qualifier("Doctor")
 private Person person;
 public String toString(){
 return person.personName();
 }
}

注意 @Qualifier 注解括號里面的必須是 bean 的名字,即 Person 接口實現(xiàn)類的類名首字母小寫如“doctor”畜晰,否則會報錯砾莱。

3??@Resource

@Resource 注解作用與 @Autowired 非常相似。先看一下 @Resource:

@Service
public class School{
 @Resource(name = "teacher")
 private Teacher teacher;
 @Resource(type = Student.class)
 private Student student;
 public String toString(){
  return teacher + "\n" + student;
 }
}

4??@Inject

  1. @Inject 是JSR330 (Dependency Injection for Java)中的規(guī)范舷蟀,需要導入javax.inject.Inject jar包恤磷,才能實現(xiàn)注入。
  2. @Inject 可以作用 constructor野宜、method扫步、field 上。
  3. @Inject 是根據(jù)類型進行自動裝配的匈子。如果需要按名稱進行裝配河胎,則需要配合 @Named;

簡單示例:

@Inject
private Car car;

指定加入BMW組件:

@Inject
@Named("BMW")
private Car car;

@Named 的作用類似 @Qualifier

5??@Service

使用@Service虎敦,可以更加簡化.xml文件配置游岳。因為Spring的配置文件里面還有12行~14行三個bean,應用Spring配置文件里面一個自動掃描的標簽其徙,可以把這三個bean也給去掉胚迫,增強Java代碼的內聚性并進一步減少配置文件。先看一下配置文件:

<context:component-scan base-package="com.wg" />

配置文件看起來特別清爽唾那。下面以School.java為例访锻,Teacher.java和Student.java同理:

@Service 
public class School{ 
 @Autowired 
 private Teacher teacher; 
 @Autowired 
 private Student student; 
 public String toString(){ 
  return teacher + "\n" + student; 
 }
} 

這樣,School.java在Spring容器中存在的形式就是"school",即可以通過ApplicationContext的getBean("school")方法來得到School.java期犬。@Service注解河哑,其實做了兩件事情:

  1. 聲明School.java是一個bean。這點很重要龟虎,因為School.java是一個bean璃谨,其他的類才可以使用@Autowired將School作為一個成員變量自動注入。
  2. School.java在bean中的id是"school"鲤妥,即類名且首字母小寫佳吞。

如果不想用這種形式怎么辦,就想讓School.java在Spring容器中的名字叫做"School"棉安,可以的:

@Service
@Scope("prototype")
public class School{
 @Autowired
 private Teacher teacher;
 @Autowired
 private Student student;
 public String toString(){
  return "TeacherName:" + teacher + "\nStudentName:" + student;
 }
}

這樣容达,就可以通過ApplicationContext的getBean(“School”)方法來得到 School.java 了。

因為 Spring 默認產(chǎn)生的 bean 是單例的垂券,如果不想使用單例花盐,xml 文件里面可以在 bean 里面配置 @Scope 屬性。注解也一 樣菇爪,配置 @Scope 即可算芯,默認是“singleton”即單例,“prototype”表示原型即每次都會 new 一個新的出來凳宙。

注意:
假如 school 包下有 Teacher熙揍、wg 包下也有 Teacher,它們二者都加了 @Service 注解氏涩,那么在 School.java 中即使明確表示要引用的是 wg 包下的 Teacher届囚,程序運行的時候依然會報錯。這是因為是尖,兩個 Teacher 都使用 @Service 注解標注意系,意味著兩個 bean 的名字都是“teacher”,那么在 School.java 中自動裝配的是哪個 Teacher 呢饺汹?不明確蛔添,因此,Spring容器會拋出BeanDefinitionStoreException兜辞,Caused by:
org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name ‘teacher’ for bean class [com.wg.uu.Teacher] conflicts with existing, non-compatible bean definition of same name and class [com.wg.school.Teacher]

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末迎瞧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子逸吵,更是在濱河造成了極大的恐慌凶硅,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扫皱,死亡現(xiàn)場離奇詭異足绅,居然都是意外死亡压语,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門编检,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扰才,你說我怎么就攤上這事允懂。” “怎么了衩匣?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵蕾总,是天一觀的道長。 經(jīng)常有香客問我琅捏,道長生百,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任柄延,我火速辦了婚禮蚀浆,結果婚禮上,老公的妹妹穿的比我還像新娘搜吧。我一直安慰自己市俊,他們只是感情好,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布滤奈。 她就那樣靜靜地躺著摆昧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜒程。 梳的紋絲不亂的頭發(fā)上绅你,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機與錄音昭躺,去河邊找鬼忌锯。 笑死,一個胖子當著我的面吹牛领炫,可吹牛的內容都是我干的汉规。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼驹吮,長吁一口氣:“原來是場噩夢啊……” “哼针史!你這毒婦竟也來了?” 一聲冷哼從身側響起碟狞,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤啄枕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后族沃,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體频祝,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡泌参,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了常空。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沽一。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖漓糙,靈堂內的尸體忽然破棺而出铣缠,到底是詐尸還是另有隱情,我是刑警寧澤昆禽,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布蝗蛙,位于F島的核電站,受9級特大地震影響醉鳖,放射性物質發(fā)生泄漏捡硅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一盗棵、第九天 我趴在偏房一處隱蔽的房頂上張望壮韭。 院中可真熱鬧,春花似錦纹因、人聲如沸泰涂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逼蒙。三九已至,卻和暖如春寄疏,著一層夾襖步出監(jiān)牢的瞬間是牢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工陕截, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留驳棱,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓农曲,卻偏偏與公主長得像社搅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子乳规,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內容

  • 2.1 我們的理念是:讓別人為你服務 IoC是隨著近年來輕量級容器(Lightweight Container)的...
    好好學習Sun閱讀 2,713評論 0 11
  • Spring容器高層視圖 Spring 啟動時讀取應用程序提供的Bean配置信息形葬,并在Spring容器中生成一份相...
    Theriseof閱讀 2,812評論 1 24
  • 1.Spring整體架構 1)核心容器(Core Container) Core模塊,主要包含了Spring框架基...
    Sponge1128閱讀 1,062評論 0 1
  • 參考W3C Spring教程 Spring致力于J2EE應用的各種解決方案暮的,而不僅僅專注于某一層解決方案笙以。可以說S...
    王偵閱讀 1,171評論 0 6
  • 還記得沒上初中前拆祈,我覺得我對生活的感知是很強的。 我記得小的時候倘感,很喜歡我家門口的那條巷子放坏,因為它坑坑洼洼的,在每...
    桐雨羲閱讀 2,098評論 2 8