spring注解

什么是注解

傳統(tǒng)的Spring做法是使用.xml文件來對bean進(jìn)行注入或者是配置aop承疲、事物施逾,這么做有兩個(gè)缺點(diǎn):

1托猩、如果所有的內(nèi)容都配置在.xml文件中,那么.xml文件將會十分龐大旗闽;如果按需求分開.xml文件,那么.xml文件又會非常多蜜另∈适遥總之這將導(dǎo)致配置文件的可讀性與可維護(hù)性變得很低

2、在開發(fā)中在.java文件和.xml文件之間不斷切換举瑰,是一件麻煩的事亭病,同時(shí)這種思維上的不連貫也會降低開發(fā)的效率

為了解決這兩個(gè)問題,Spring引入了注解嘶居,通過"@XXX"的方式罪帖,讓注解與Java Bean緊密結(jié)合促煮,既大大減少了配置文件的體積,又增加了Java Bean的可讀性與內(nèi)聚性整袁。

本篇文章菠齿,講講最重要的三個(gè)Spring注解,也就是@Autowired坐昙、@Resource和@Service绳匀,希望能通過有限的篇幅說清楚這三個(gè)注解的用法。

不使用注解

先看一個(gè)不使用注解的Spring示例炸客,在這個(gè)示例的基礎(chǔ)上疾棵,改成注解版本的,這樣也能看出使用與不使用注解之間的區(qū)別痹仙,先定義一個(gè)老虎:

public class Tiger
{
    private String tigerName = "TigerKing";
    
    public String toString()
    {
        return "TigerName:" + tigerName;
    }
}

再定義一個(gè)猴子:

public class Monkey
{
    private String monkeyName = "MonkeyKing";
    
    public String toString()
    {
        return "MonkeyName:" + monkeyName;
    }
}

再定義個(gè)動物園:

public class Zoo
{
   private Tiger tiger;
   private Monkey monkey;
   
   public void setTiger(Tiger tiger)
   {
       this.tiger = tiger;
   }
   
   public void setMonkey(Monkey monkey)
   {
       this.monkey = monkey;
   }
   
   public Tiger getTiger()
   {
       return tiger;
   }
   
   public Monkey getMonkey()
   {
       return monkey;
   }
   
   public String toString()
   {
       return tiger + "\n" + monkey;
   }
}

spring配置文件的代碼pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
    xmlns="http://www.springframework.org/schema/beans"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.2.xsd"
    default-autowire="byType">
    
    <bean id="zoo" class="com.xrq.bean.Zoo" >
        <property name="tiger" ref="tiger" />
        <property name="monkey" ref="monkey" />
    </bean>
    <bean id="tiger" class="com.xrq.domain.Tiger" />
    <bean id="monkey" class="com.xrq.domain.Monkey" />
</beans>

如果很熟悉了是尔,就當(dāng)復(fù)習(xí)一遍了。

@Autowired

@Autowired顧名思義开仰,就是自動裝配拟枚,其作用是為了消除代碼Java代碼里面的getter/setter與bean屬性中的property。當(dāng)然众弓,getter看個(gè)人需求恩溅,如果私有屬性需要對外提供的話,應(yīng)當(dāng)予以保留谓娃。

因此脚乡,我們引入@Autowired注解

先看一下spring配置文件怎么寫:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
    xmlns="http://www.springframework.org/schema/beans"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.2.xsd">
    
    <context:component-scan base-package="com.xrq" />
    
    <bean id="zoo" class="com.xrq.bean.Zoo" />
    <bean id="tiger" class="com.xrq.domain.Tiger" />
    <bean id="monkey" class="com.xrq.domain.Monkey" />
    
</beans>

注意第10行,使用必須告訴spring一下我要使用注解了滨达,告訴的方式有很多每窖,<context:component-scan base-package="com.xrq" />是一種最簡單的,spring會自動掃描com.xrq路徑下的注解弦悉。

看到第12行窒典,原來zoo里面應(yīng)當(dāng)注入兩個(gè)屬性tiger、monkey稽莉,現(xiàn)在不需要注入了瀑志。再看下,Zoo.java也很方便污秆,把getter/setter都可以去掉:

{
    @Autowired
    private Tiger tiger;
    
    @Autowired
    private Monkey monkey;
    
    public String toString()
    {
        return tiger + "\n" + monkey;
    }
}

這里@Autowired注解的意思就是劈猪,當(dāng)Spring發(fā)現(xiàn)@Autowired注解時(shí),將自動在代碼上下文中找到和其匹配(默認(rèn)是類型匹配)的Bean良拼,并自動注入到相應(yīng)的地方去战得。

有一個(gè)細(xì)節(jié)性的問題是,假如bean里面有兩個(gè)property庸推,Zoo.java里面又去掉了屬性的getter/setter并使用@Autowired注解標(biāo)注這兩個(gè)屬性那會怎么樣常侦?答案是Spring會按照xml優(yōu)先的原則去Zoo.java中尋找這兩個(gè)屬性的getter/setter浇冰,導(dǎo)致的結(jié)果就是初始化bean報(bào)錯。

OK聋亡,假設(shè)此時(shí)我把.xml文件的13行肘习、14行兩行給去掉,再運(yùn)行坡倔,會拋出異常:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'Zoo': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.xrq.domain.Tiger com.xrq.bean.Zoo.ttiger; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.xrq.domain.Tiger] 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)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:835)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
    at com.xrq.test.MyTest.main(MyTest.java:13)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.xrq.domain.Tiger com.xrq.bean.Zoo.ttiger; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.xrq.domain.Tiger] 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$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:571)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
    ... 13 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.xrq.domain.Tiger] 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.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1119)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:543)
    ... 15 more

因?yàn)槠澹珸Autowired注解要去尋找的是一個(gè)Bean,Tiger和 Monkey的Bean定義都給去掉了罪塔,自然就不是一個(gè)Bean了投蝉,Spring容器找不到也很好理解。那么征堪,如果屬性找不到我不想讓Spring容器拋 出異常瘩缆,而就是顯示null,可以嗎请契?可以的咳榜,其實(shí)異常信息里面也給出了提示了夏醉,就是將@Autowired注解的required屬性設(shè)置為false 即可:

public class Zoo
{
    @Autowired(required = false)
    private Tiger tiger;
    
    @Autowired(required = false)
    private Monkey monkey;
    
    public String toString()
    {
        return tiger + "\n" + monkey;
    }
}

此時(shí)爽锥,找不到tiger、monkey兩個(gè)屬性畔柔,Spring容器不再拋出異而是認(rèn)為這兩個(gè)屬性為null氯夷。

@Autowired接口注入

上面的比較簡單,我們只是簡單注入一個(gè)Java類靶擦,那么如果有一個(gè)接口腮考,有多個(gè)實(shí)現(xiàn),Bean里引用的是接口名玄捕,又該怎么做呢踩蔚?比如有一個(gè)Car接口:

public interface Car
{
    public String carName();
}
@Service
public class Benz implements Car
{
    public String carName()
    {
        return "Benz car";
    }
}

寫一個(gè)CarFactory,引用Car:

@Service
public class CarFactory
{
    @Autowired
    private Car car;
    
    public String toString()
    {
        return car.carName();
    }
}

不用說枚粘,一定是報(bào)錯的馅闽,Car接口有兩個(gè)實(shí)現(xiàn)類,Spring并不知道應(yīng)當(dāng)引用哪個(gè)實(shí)現(xiàn)類馍迄。這種情況通常有兩個(gè)解決辦法:

1福也、刪除其中一個(gè)實(shí)現(xiàn)類,Spring會自動去base-package下尋找Car接口的實(shí)現(xiàn)類攀圈,發(fā)現(xiàn)Car接口只有一個(gè)實(shí)現(xiàn)類暴凑,便會直接引用這個(gè)實(shí)現(xiàn)類

2、實(shí)現(xiàn)類就是有多個(gè)該怎么辦赘来?此時(shí)可以使用@Qualifier注解:

@Service
public class CarFactory
{
   @Autowired
   @Qualifier("BMW")
   private Car car;
   
   public String toString()
   {
       return car.carName();
   }
}

注意@Qualifier注解括號里面的應(yīng)當(dāng)是Car接口實(shí)現(xiàn)類的類名现喳,我之前試的時(shí)候一直以為是bean的名字凯傲,所以寫了"bMW",結(jié)果一直報(bào)錯拿穴。

@Resource

把@Resource注解放在@Autowired下面說泣洞,是因?yàn)樗鼈冏饔梅浅O嗨疲@個(gè)就簡單說了默色,例子過后點(diǎn)明一下@Resource和@Autowired的區(qū)別球凰。先看一下@Resource,直接寫Zoo.java了:

@Service
public class Zoo
{
    @Resource(name = "tiger")
    private Tiger tiger;
    
    @Resource(type = Monkey.class)
    private Monkey monkey;
    
    public String toString()
    {
        return tiger + "\n" + monkey;
    }
}

這是詳細(xì)一些的用法腿宰,說一下@Resource的裝配順序:

1呕诉、@Resource后面沒有任何內(nèi)容,默認(rèn)通過name屬性去匹配bean吃度,找不到再按type去匹配

2甩挫、指定了name或者type則根據(jù)指定的類型去匹配bean

3、指定了name和type則根據(jù)指定的name和type去匹配bean椿每,任何一個(gè)不匹配都將報(bào)錯

然后伊者,區(qū)分一下@Autowired和@Resource兩個(gè)注解的區(qū)別:

1、@Autowired默認(rèn)按照byType方式進(jìn)行bean匹配间护,@Resource默認(rèn)按照byName方式進(jìn)行bean匹配

2亦渗、@Autowired是Spring的注解,@Resource是J2EE的注解汁尺,這個(gè)看一下導(dǎo)入注解的時(shí)候這兩個(gè)注解的包名就一清二楚了

Spring屬于第三方的法精,J2EE是Java自己的東西,因此痴突,建議使用@Resource注解搂蜓,以減少代碼和Spring之間的耦合。

@Service

上面這個(gè)例子辽装,還可以繼續(xù)簡化帮碰,因?yàn)閟pring的配置文件里面還有12行~14行三個(gè)bean,下一步的簡化是把這三個(gè)bean也給去掉拾积,使得spring配置文件里面只有一個(gè)自動掃描的標(biāo)簽殉挽,增強(qiáng)Java代碼的內(nèi)聚性并進(jìn)一步減少配置文件。

要繼續(xù)簡化殷勘,可以使用@Service此再。先看一下配置文件,當(dāng)然是全部刪除了:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
    xmlns="http://www.springframework.org/schema/beans"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.2.xsd">
    
    <context:component-scan base-package="com.xrq" />
    
</beans>

是不是瞬間舒服多了玲销?起碼我覺得是的输拇。OK,下面以Zoo.java為例贤斜,其余的Monkey.java和Tiger.java都一樣:

@Service
public class Zoo
{
    @Autowired
    private Tiger ttiger;
    
    @Autowired
    private Monkey mmonkey;
    
    public String toString()
    {
        return ttiger + "\n" + mmonkey;
    }
}

這樣策吠,Zoo.java在Spring容器中存在的形式就是"zoo"逛裤,即可以通過ApplicationContext的getBean("zoo")方法來得到Zoo.java。@Service注解猴抹,其實(shí)做了兩件事情:

1带族、聲明Zoo.java是一個(gè)bean,這點(diǎn)很重要蟀给,因?yàn)閆oo.java是一個(gè)bean蝙砌,其他的類才可以使用@Autowired將Zoo作為一個(gè)成員變量自動注入

2、Zoo.java在bean中的id是"zoo"跋理,即類名且首字母小寫

如果择克,我不想用這種形式怎么辦,就想讓Zoo.java在Spring容器中的名字叫做"Zoo"前普,可以的:

@Service
@Scope("prototype")
public class Zoo
{
    @Autowired
    private Monkey monkey;
    @Autowired
    private Tiger tiger;
    
    public String toString()
    {
        return "MonkeyName:" + monkey + "\nTigerName:" + tiger;
    }
}

這樣肚邢,就可以通過ApplicationContext的getBean("zoo")方法來得到Zoo.java了。

這里我還多加了一個(gè)@Scope注解拭卿,應(yīng)該 很好理解骡湖。因?yàn)镾pring默認(rèn)產(chǎn)生的bean是單例的,假如我不想使用單例怎么辦峻厚,xml文件里面可以在bean里面配置scope屬性响蕴。注解也是一 樣,配置@Scope即可目木,默認(rèn)是"singleton"即單例换途,"prototype"表示原型即每次都會new一個(gè)新的出來懊渡。

補(bǔ)充細(xì)節(jié)

最后再補(bǔ)充一個(gè)我發(fā)現(xiàn)的細(xì)節(jié)刽射。假如animal包下有Tiger、domain包下也有Tiger剃执,它們二者都加了@Service注解誓禁,那么在Zoo.java中即使明確表示我要引用的是domain包下的Tiger,程序運(yùn)行的時(shí)候依然會報(bào)錯肾档。

細(xì)想摹恰,其實(shí)這很好理解,兩個(gè)Tiger都使 用@Service注解標(biāo)注怒见,意味著兩個(gè)Bean的名字都是"tiger"俗慈,那么我在Zoo.java中自動裝配的是哪個(gè)Tiger呢?不明確遣耍,因 此闺阱,Spring容器會拋出BeanDefinitionStoreException異常,Caused by:

Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'monkey' for bean class [com.xrq.domain.Monkey] conflicts with existing, non-compatible bean definition of same name and class [com.xrq.animal.Monkey]

注:這文章水了好多廢話,適合新手看,寫了好久,給個(gè)愛心唄!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末舵变,一起剝皮案震驚了整個(gè)濱河市酣溃,隨后出現(xiàn)的幾起案子瘦穆,更是在濱河造成了極大的恐慌,老刑警劉巖赊豌,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扛或,死亡現(xiàn)場離奇詭異,居然都是意外死亡碘饼,警方通過查閱死者的電腦和手機(jī)熙兔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來艾恼,“玉大人黔姜,你說我怎么就攤上這事〉傥” “怎么了秆吵?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長五慈。 經(jīng)常有香客問我纳寂,道長,這世上最難降的妖魔是什么泻拦? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任毙芜,我火速辦了婚禮,結(jié)果婚禮上争拐,老公的妹妹穿的比我還像新娘腋粥。我一直安慰自己,他們只是感情好架曹,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布隘冲。 她就那樣靜靜地躺著,像睡著了一般绑雄。 火紅的嫁衣襯著肌膚如雪展辞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天万牺,我揣著相機(jī)與錄音罗珍,去河邊找鬼。 笑死脚粟,一個(gè)胖子當(dāng)著我的面吹牛覆旱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播核无,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼扣唱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起画舌,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤堕担,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后曲聂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體霹购,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年朋腋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了齐疙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,622評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡旭咽,死狀恐怖贞奋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情穷绵,我是刑警寧澤轿塔,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站仲墨,受9級特大地震影響勾缭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜目养,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一俩由、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧癌蚁,春花似錦幻梯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至洽洁,卻和暖如春痘系,著一層夾襖步出監(jiān)牢的瞬間菲嘴,已是汗流浹背饿自。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留龄坪,地道東北人昭雌。 一個(gè)月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像健田,于是被迫代替她去往敵國和親烛卧。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評論 2 348