1. 程式人生 > >終極講解,看了立馬懂 --》Spring註解@Component、@Repository、@Service、@Controller @Resource、@Autowired、@Qualifier 解析

終極講解,看了立馬懂 --》Spring註解@Component、@Repository、@Service、@Controller @Resource、@Autowired、@Qualifier 解析

我們在使用spring的時候經常會用到這些註解,那麼這些註解到底有什麼區別呢。我們先來看程式碼

同樣分三層來看:

Action 層:

package com.ulewo.ioc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class IocAction {
    @Autowired
    private IocService service;
   
    public void add(){
        service.add();
    }
}


service層:(service就直接定義類了,沒有定義介面,定義介面也是一樣的)

package com.ulewo.ioc;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

@Service
public class IocService {
    @Resource
    private IIocDao iocDao;
    public void add(){
        iocDao.add();
    }
}


Dao層

先定義一個介面

package com.ulewo.ioc;

public interface IIocDao {
    public void add();
}


然後實現類:

package com.ulewo.ioc;

import org.springframework.stereotype.Repository;

@Repository
public class IocDao implements IIocDao{
    public void add(){
        System.out.println("呼叫了dao");
    }
}


然後spring的配置,這個配置就很簡單了,因為是基於註解的,我們不需要再xml中來定義很多

applicationContext.xml

讓spring自動掃描包就行了。

然後是我們的測試類:

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,要為該屬性賦值我們就用著三個。我們看上面的程式碼可以看到這三個都是定義在一個屬性上的,比如

@Resource
private IIocDao iocDao;

@Autowired
private 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;

@Repository
public 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的名稱就行,就不會錯亂。


說了這麼多,不知道對著幾個註解是不是瞭解多一點了呢,貌似這些註解 沒有根本上的區別,就看你習慣怎麼用了。拿程式碼多跑幾次,然後根據自己