咱們在使用spring的時候常常會用到這些註解,那麼這些註解到底有什麼區別呢。咱們先來看代碼css
一樣分三層來看:java
Action 層:spring
package com.ulewo.ioc;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;@Controllerpublic class IocAction { @Autowired private IocService service; public void add(){ service.add(); } }
service層:(service就直接定義類了,沒有定義接口,定義接口也是同樣的)
app
package com.ulewo.ioc;import javax.annotation.Resource;import org.springframework.stereotype.Service;@Servicepublic class IocService { @Resource private IIocDao iocDao; public void add(){ iocDao.add(); } }
Dao層
測試
先定義一個接口
spa
package com.ulewo.ioc;public interface IIocDao { public void add(); }
而後實現類:
.net
package com.ulewo.ioc;import org.springframework.stereotype.Repository;@Repositorypublic class IocDao implements IIocDao{ public void add(){ System.out.println("調用了dao"); } }
而後spring的配置,這個配置就很簡單了,由於是基於註解的,咱們不須要再xml中來定義不少
code
applicationContext.xmlcomponent
<?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:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd"> <context:annotation-config /> <context:component-scan base-package="com.ulewo.ioc" > </context:component-scan> </beans>
讓spring自動掃描包就好了。orm
而後是咱們的測試類:
IocTest:
package com.ulewo.ioc;import junit.framework.TestCase;import org.springframework.beans.factory.BeanFactory;import org.springframework.context.support.ClassPathXmlApplicationContext;public class IocTest extends TestCase{ public void testIoc(){ BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml"); IocAction action = factory.getBean("iocAction", IocAction.class); action.add(); } }
運行後,咱們會發現 控制檯打印:調用了dao
@Component、@Repository、@Service、@Controller @Resource、@Autowired、@Qualifier
這幾個基本都用到了 除了 @Component @Qualifier
咱們觀察會發現@Repository、@Service、@Controller 這幾個是一個類型,其實@Component 跟他們也是一個類型的
Spring 2.5 中除了提供 @Component 註釋外,還定義了幾個擁有特殊語義的註釋,它們分別是:@Repository、@Service和 @Controller 其實這三個跟@Component 功能是等效的
@Service用於標註業務層組件(咱們一般定義的service層就用這個)
@Controller用於標註控制層組件(如struts中的action)
@Repository用於標註數據訪問組件,即DAO組件
@Component泛指組件,當組件很差歸類的時候,咱們可使用這個註解進行標註。
這幾個註解是當你須要定義某個類爲一個bean,則在這個類的類名前一行使用@Service("XXX"),就至關於講這個類定義爲一個bean,bean名稱爲XXX; 這幾個是基於類的,咱們能夠定義名稱,也能夠不定義,不定義會默認以類名爲bean的名稱(類首字母小寫)。
而後咱們在看後面的幾個註解
@Resource、@Autowired、@Qualifier
當須要在某個類中定義一個屬性,而且該屬性是一個已存在的bean,要爲該屬性賦值咱們就用着三個。咱們看上面的代碼能夠看到這三個都是定義在一個屬性上的,好比
@Resourceprivate IIocDao iocDao;
@Autowiredprivate IocService service;
那這幾個到底有什麼區別呢?
咱們先看@Resource,它是javax.annotation.Resource; 這個包中,也就是說是javaEE中的,並非spring中的
並且@Resource("xxx") 是能夠定義bean名稱的,就是說我這個屬性要用那個bean來賦值。
@Autowired,它是org.springframework.beans.factory.annotation.Autowired 是這個包中,它是spring的包。
並且它沒有@Autowired("xxx"),那我要爲這個bean定義名稱怎麼辦這個時候能夠用@Qualifier("xxx") 這個也是spring中的。這個xxx定義bean名稱有什麼用呢?咱們回頭看下剛纔的代碼。
在IIocDao 這個接口中,咱們定義的實現類IocDao 只有一個,好那麼咱們再定義一個實現類:
package com.ulewo.ioc;import org.springframework.stereotype.Repository;@Repositorypublic class IocDao2 implements IIocDao{ public void add(){ System.out.println("調用了dao2"); } }
其餘不變,咱們再運行:testIoc(),控制檯打印出 調用了dao,因此在service層中
@Resource
private IIocDao iocDao;
這個iocDao 注入的是IocDao 這個實現。奇怪了,它怎麼知道我要調用哪一個實現呢?
好咱們修改一下,把 private IIocDao iocDao;改一下,改爲 private IIocDao iocDaox 把屬性名改一下,再運行,會報錯:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.ulewo.ioc.IIocDao] is defined: expected single matching bean but found 2: iocDao,iocDao2
錯誤很明顯啊,有兩個bean iocDao和iocDao2,可是咱們的是iocDaox因此找不到了。因此能夠看出來在用 @Repository註解來生成bean的時候,若是沒有定義名稱那麼就會根據類名來生成。因此咱們要調用第二個實現的時候能夠 定義爲private IIocDao iocDao2 。咱們再運行:調用了dao2,因此能夠根據屬性名來區分,到底注入那個bean。可是有的人說,我不想定義bean名稱跟類實現同樣,我要定義其餘的,那怎麼玩呢,方法有2種:
第一種:咱們在生成bean的時候就給bean定義個名稱
@Repository("myIocDao")
public class IocDao implements IIocDao{
public void add(){
System.out.println("調用了dao");
}
}
固然@Service是同樣的,這樣就把這個實現定義爲myIocDao了,而不是默認的類名 iocDao。
那麼咱們在使用這個bean的時候就要這麼定義了:
@Resource
private IIocDao myIocDao;
運行 輸出:調用了dao
若是你這裏不是用的 myIocDao,你又多加了一個x,成了myIocDaox,你運行會是這樣的:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.ulewo.ioc.IIocDao] is defined: expected single matching bean but found 2: myIocDao,iocDao2
因此,要自定義bean的名稱能夠在類註解的時候指定。
第二種:在注入bean的時候指定名稱:
先看@Resource
咱們這麼定義下:
@Resource(name="iocDao")
private IIocDao xx;
注意:
@Repository
public class IocDao implements IIocDao{
public void add(){
System.out.println("調用了dao");
}
}
這裏仍是用會默認的,也就是這個實現對應的是 iocDao這bean。若是你要爲這個類指定別名bean,@Repository("myIocDao"),那@Resource(name="myIocDao") 就要這麼寫了。就是這裏的name要跟實現類對應的bean名稱保持一致。private IIocDao xx; 這個屬性名就隨便寫了。
運行:調用了dao
若是用Autowired就要這麼寫了
@Autowired
@Qualifier("iocDao")
private IIocDao xx;
由於Autowired 不能像Resource 那樣帶個參數指定一個name,就要用Qualifier來指定了。
並且還能夠這麼用
@Resource
@Qualifier("iocDao")
private IIocDao xx;
等同於
@Resource(name="iocDao")
private IIocDao xx;
記住一點:@Resource的做用至關於@Autowired,只不過@Autowired按byType自動注入,若是發現找到多個bean,則,又按照byName方式比對,若是還有多個,則報出異常 而@Resource默認按 byName自動注入罷了。其實spring註解,最經常使用的仍是根據名稱,根據類型啊,構造方法啊,用的很是少。因此在多個實現的時候咱們定義好bean的名稱就行,就不會錯亂。