1. 程式人生 > >詳細解析@Resource和@Autowired的區別 , 以及@Qualifier的作用

詳細解析@Resource和@Autowired的區別 , 以及@Qualifier的作用

首先 .
@Resource是javax.annotation 包中的註解類 , 是jdk中封裝的 .
@AutoWired是spring的中註解,依賴於spring上下文.

相同點:
@Resource 和 @Autowired 都可以用在類中的field 或者function 上 , 在類初始化的時候 , 自動為field 賦值 , 自動為function注入引數並且執行該方法(不僅僅侷限於set方法) .

不同點:
1. @Autowired 寫在建構函式上,為構造器注入引數 , @Resource不能建構函式上.
2. @Autowired是根據注入類的型別來尋找bean的 , 如果同一個Type的類注入了多個id(或者name) 不一樣的bean , 那麼用@Autowired就無法準確的找到是哪個bean了, 這個時候就會丟擲一個異常. 如果放在建構函式上 , 那麼spring預設會使用該帶參的構造器初始化類 , 當autowired傳入required=false 時 , 如果初始化時沒有找到注入的bean , 且該bean仍然有寫空參的建構函式 , 則spring會自動呼叫空參的建構函式初始化 , 但是如果沒有寫空參建構函式 , 在會丟擲異常.
3. @Resource分兩種情況 :

  1. 在不傳引數或者傳入空參的情況下 , @Resource預設根據注入bean的欄位名來尋找bean (若放在function上 , 如果該function為set方法, 則bean名稱解析為set對應的欄位名 , 如果不是set方法 , 則bean解析為function的方法名) , 如果找不到 , 在根據型別來尋找對應的bean, 如果還找不到 , 丟擲異常 , 如果找不到與欄位名相匹配的bean , 但是型別匹配的卻有多個 , 也丟擲異常 ;
  2. 在傳入確定引數的情況下 , @Resouce或根據傳入的name值來尋找這個名稱的bean , 如果找不到則丟擲異常 , 或者根據type值來尋找這個型別的bean , 也可以同時指定name和type.

@Qualifier 可以寫在field 或者function傳入引數的引數型別前面 , 用來指定注入bean的名稱 ,如果不指定value, 那麼預設是空名稱, 也是可以編譯通過的 , 但是無法匹配到對應的bean (以兩個同一interface的實現注入不同名稱的bean來測試 , 如果本身只有一個對應的bean , 或者僅僅通過@Resource 或 @Autowired就可以找到對應的bean , 就無法測試出來@Qualifier的效果了 ) ,所以一般情況下 , 使用@Qualifier都需要傳入value引數 , 指定bean的名稱 ,

最後注意一點 , @Resource雖然是JDK中的註解類 , 但是jdk中並沒有具體的處理方式 , 需要依賴於其他框架或者工具才能實現具體功能 , 如果不載入spring容器 , 單獨使用@Resource註解 , 是沒有任何作用的.

下面是測試用的程式碼 , 很簡單的例子 , 感興趣的朋友 , 可以自己改一改userService來測試一下各種情況 .

beans:

<?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.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

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

</beans>

interface

public interface UserDao {


}

實現:

@Component("userDao")
public class UserDaoImpl implements UserDao {

    private int daoId = 1;

    @Override
    public String toString() {
        return "UserDaoImpl{" +
                "daoId=" + daoId +
                '}';
    }

}
@Component("userDao2")
public class UserDaoImpl2 implements UserDao {

    private int daoId = 2;


    @Override
    public String toString() {
        return "UserDaoImpl{" +
                "daoId=" + daoId +
                '}';
    }

}

service

@Component
public class UserService {

    private UserDao userDao;

    public UserService(){
        System.out.println("this is constructor");
    }

//    @Autowired(required = false)
    public UserService(UserDao userDao){
        System.out.println("this is constructor with paramater");
        this.userDao = userDao;
    }

    public void getDao(){
        System.out.println(this);
        System.out.println(userDao);
    }

    public UserDao getUserDao() {
        return userDao;
    }



    @Autowired
    public void setUserDao(@Qualifier("userDao2") UserDao userDao) {
        this.userDao = userDao;
    }


    public void userDao2(UserDao userDao){
        System.out.println("this is normal mothed");
        this.userDao = userDao;
    }
}

jUnit測試:

public class UserServiceTest {

    @Test
    public void testGetDao() throws Exception {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        System.out.println("----");
        UserService userService = (UserService)context.getBean("userService");
        userService.getDao();
    }
}