【Java】@Autowired和@Resource

@Autowired和@Resource這兩個(gè)注解最大的區(qū)別:

  • @Autowired 根據(jù)類型注入
  • @Resource 根據(jù)名稱注入

以上是這兩個(gè)注解最主要的裝配方式,具體使用方式見下方。
以下只針對(duì)于一個(gè)接口有一個(gè)或多個(gè)實(shí)現(xiàn)類的情況進(jìn)行討論。沒有實(shí)現(xiàn)類的情況不討論,個(gè)人覺得自動(dòng)注入允許為空的情況是十分不安全的,實(shí)際開發(fā)中也沒有太大意義。

@Autowired

1.接口與實(shí)現(xiàn)類一一對(duì)應(yīng)

接口:

package com.example.demo.service;

/**
 * @author chenhy
 * @date 2021/4/11
 */
public interface IUserService {
    void say();
}

實(shí)現(xiàn)類01:

package com.example.demo.service.impl;

import com.example.demo.service.IUserService;
import org.springframework.stereotype.Service;

/**
 * @author chenhy
 * @date 2021/4/11
 */
@Service
public class UserServiceImpl01 implements IUserService {
    @Override
    public void say() {
        System.out.println("I am UserServiceImpl01.................");
    }
}

測(cè)試類:

package com.example.demo.test;

import com.example.demo.service.IUserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @author chenhy
 * @date 2021/4/11
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserTest {

    @Autowired
    IUserService userService;

    @Test
    public void test() {
        userService.say();
    }
}

運(yùn)行測(cè)試方法,控制臺(tái)輸出“I am UserServiceImpl01.................”。
此時(shí),Spring容器中只有一個(gè)IUserService 的實(shí)現(xiàn)類UserServiceImpl01 ,byType進(jìn)行注入時(shí),會(huì)自動(dòng)找到實(shí)現(xiàn)類UserServiceImpl01進(jìn)行注入。從控制臺(tái)的打印結(jié)果我們也可以看出,調(diào)用的是類UserServiceImpl01的方法。驗(yàn)證了@Autowired是根據(jù)類型注入的觀點(diǎn)。

2.接口與實(shí)現(xiàn)類的關(guān)系為一對(duì)多

新建實(shí)現(xiàn)類02:

package com.example.demo.service.impl;

import com.example.demo.service.IUserService;
import org.springframework.stereotype.Service;

/**
 * @author chenhy
 * @date 2021/4/11
 */
@Service
public class UserServiceImpl02 implements IUserService {
    @Override
    public void say() {
        System.out.println("I am UserServiceImpl02.................");
    }
}

運(yùn)行測(cè)試方法,控制臺(tái)報(bào)錯(cuò)如下:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.example.demo.service.IUserService' available: expected single matching bean but found 2: userServiceImpl01,userServiceImpl02
意思就是有多個(gè)實(shí)現(xiàn)類,程序不知道到底該注入哪個(gè)實(shí)現(xiàn)類了。

測(cè)試類處理如下:

package com.example.demo.test;

import com.example.demo.service.IUserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @author chenhy
 * @date 2021/4/11
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserTest {

    @Autowired
    @Qualifier("userServiceImpl02")
    IUserService userService;

    @Test
    public void test() {
        userService.say();
    }
}

運(yùn)行測(cè)試方法,控制臺(tái)輸出“I am UserServiceImpl02.................”。
我們新增了@Qualifier注解,該注解與@Autowired結(jié)合使用,可以在一個(gè)接口有多個(gè)實(shí)現(xiàn)類的情況下,指定注入的實(shí)現(xiàn)類的名稱。此處,而我們注入了第二個(gè)實(shí)現(xiàn)類UserServiceImpl02。(注意,Qualifier注解中的名稱首字母為小寫)。

@Autowired+@Qualifier的使用,實(shí)現(xiàn)了bean自動(dòng)注入時(shí),先按照類型再按照名稱進(jìn)行注入的功能。

@Resource

1.根據(jù)名稱注入(byName)

新建實(shí)現(xiàn)類:

package com.example.demo.service.impl;

import com.example.demo.service.IUserService;
import org.springframework.stereotype.Service;

/**
 * @author chenhy
 * @date 2021/4/11
 */
@Service
public class UserService implements IUserService {
    @Override
    public void say() {
        System.out.println("I am UserService.................");
    }
}

修改測(cè)試類如下:

package com.example.demo.test;

import com.example.demo.service.IUserService;
import com.example.demo.service.impl.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

/**
 * @author chenhy
 * @date 2021/4/11
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserTest {

//    @Autowired
//    @Qualifier("userServiceImpl02")
    @Resource
    IUserService userService;

    @Test
    public void test() {
        userService.say();
    }
}

其他文件不做改動(dòng)。
現(xiàn)在的整體情況是,IUserService 有3個(gè)實(shí)現(xiàn)類,如果按類型注入的話肯定是失敗的。

運(yùn)行測(cè)試方法,控制臺(tái)輸出“I am UserService.................”。
由此可見,@Resource在進(jìn)行bean注入時(shí),首先會(huì)按照名稱(byName)進(jìn)行裝配。

2.根據(jù)類型注入

將UserService.java全部注釋掉,再次運(yùn)行測(cè)試方法進(jìn)行測(cè)試。

運(yùn)行測(cè)試程序,此時(shí)控制臺(tái)報(bào)錯(cuò)如下:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.example.demo.test.UserTest': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.example.demo.service.IUserService' available: expected single matching bean but found 2: userServiceImpl01,userServiceImpl02
與之前測(cè)試Autowired注解的情形相同,按照類型注入失敗了。
測(cè)試類處理如下:

package com.example.demo.test;

import com.example.demo.service.IUserService;
import com.example.demo.service.impl.UserServiceImpl01;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

/**
 * @author chenhy
 * @date 2021/4/11
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserTest {

//    @Autowired
//    @Qualifier("userServiceImpl02")
    @Resource(type = UserServiceImpl01.class)
    IUserService userService;

    @Test
    public void test() {
        userService.say();
    }
}

運(yùn)行測(cè)試程序,控制臺(tái)輸出“I am UserServiceImpl01.................”。
通過在@Resource注解中指定注入的實(shí)現(xiàn)類來實(shí)現(xiàn)bean的注入。
此外,還可以在@Resource注解中指定類名稱。

總結(jié)

對(duì)比項(xiàng) @Autowired @Resource
注解來源 Spring注解 JDK注解(JSR-250標(biāo)準(zhǔn)注解,屬于J2EE)
裝配方式 默認(rèn)byType,其次byName 默認(rèn)byName,其次byType
屬性 required name、type
作用范圍 字段、setter方法、構(gòu)造器 字段、setter方法

1.處理這2個(gè)注解的BeanPostProcessor不一樣

CommonAnnotationBeanPostProcessor是處理@ReSource注解的;
AutoWiredAnnotationBeanPostProcessor是處理@AutoWired注解的。

2.注入方式不同

@Autowired只按照byType注入;
@Resource默認(rèn)按byName自動(dòng)注入,也提供按照byType注入。

3.屬性不同

@Autowired按類型裝配依賴對(duì)象,默認(rèn)情況下它要求依賴對(duì)象必須存在,如果允許null值,可以設(shè)置它required屬性為false。如果我們想使用按名稱裝配,可以結(jié)合@Qualifier注解一起使用。
@Resource有兩個(gè)中重要的屬性:name和type。name屬性指定byName,如果沒有指定name屬性,當(dāng)注解標(biāo)注在字段上,即默認(rèn)取字段的名稱作為bean名稱尋找依賴對(duì)象,當(dāng)注解標(biāo)注在屬性的setter方法上,即默認(rèn)取屬性名作為bean名稱尋找依賴對(duì)象。需要注意的是,@Resource如果沒有指定name屬性,并且按照默認(rèn)的名稱仍然找不到依賴對(duì)象時(shí), @Resource注解會(huì)回退到按類型裝配。但一旦指定了name屬性,就只能按名稱裝配了。

4.裝配順序不同

@Autowired:首先通過類型來查找bean,如果只找到一個(gè),則直接注入,如果沒有找到,則拋出異常;如果找到多個(gè)bean也會(huì)拋出異常。
解決方法一:可以在配置bean的時(shí)候加上@Primary注解,來提高優(yōu)先級(jí),這樣就不會(huì)報(bào)錯(cuò);
解決方法二:會(huì)默認(rèn)使用字段名來匹配,如果沒有匹配上,拋出異常。
如果需要直接通過bean的id來查找,可以配合@Qualifier來使用,沒有找到拋出異常。
這里重點(diǎn)需要指出,使用@Autowired 是有優(yōu)先級(jí)的,@Qualifier > 按類型找(如果找到多個(gè)繼續(xù)使用之后的策略) > @Primary > 按名字找
@Autowired通過設(shè)置required=false,在沒有找到bean的情況下,不會(huì)拋出異常。

@Resource裝配順序:
如果同時(shí)指定了name和type,則從Spring上下文中找到唯一匹配的bean進(jìn)行裝配,找不到則拋出異常。
如果指定了name,則從上下文中查找名稱(id)匹配的bean進(jìn)行裝配,找不到則拋出異常。
如果指定了type,則從上下文中找到類似匹配的唯一bean進(jìn)行裝配,找不到或是找到多個(gè),都會(huì)拋出異常。
如果既沒有指定name,又沒有指定type,則自動(dòng)按照byName方式進(jìn)行裝配;如果沒有匹配,則回退為一個(gè)原始類型進(jìn)行匹配,如果匹配則自動(dòng)裝配。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友。感恩相遇!感恩不離不棄。 中午開了第一次的黨會(huì),身份的轉(zhuǎn)變要...
    余生動(dòng)聽閱讀 10,918評(píng)論 0 11
  • 彩排完,天已黑
    劉凱書法閱讀 4,501評(píng)論 1 3
  • 表情是什么,我認(rèn)為表情就是表現(xiàn)出來的情緒。表情可以傳達(dá)很多信息。高興了當(dāng)然就笑了,難過就哭了。兩者是相互影響密不可...
    Persistenc_6aea閱讀 129,938評(píng)論 2 7

友情鏈接更多精彩內(nèi)容