天天看點

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

前言

@Autowired 和 @Resource  

這兩個注解大家想必都有在項目裡面出現過,但是真的清楚這倆玩意的用法或者說是差別麼?

一直用的都是 @Autowired ?

别人代碼用什麼就copy用什麼,反正他沒錯,俺也不會錯?

它們都是一樣的作用?隻是名字不一樣而已?

如果你存在以上這些疑問,那麼你看這篇文章必賺! 上車!

如果你不存在以上這些疑問,那麼你看這篇文章也不虧! 

正文

跟着我 了解下 @Autowired  和 @Resource   這兩位兄台

1.看看他們從哪裡來?

@Autowired :

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

@Resource :

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

從這我們可以知道,

@Autowired  是一個 spring 的注解 

@Resource

2.他們的作用是什麼?

既然說到作用,那按照咱們的風格,肯定是結合執行個體介紹,我們從不光紙上談兵。

(我知道你知道他們是用于注入的,但是你可能隻是知道,你不徹底了解)

模拟場景 一 

一個業務接口隻對應一個業務實作類:

一個 UserService 接口:

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

一個UserServiceImpl 接口實作類 :

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

首先我們   在測試的Controller裡面  使用 @Autowired   :

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

調用測試:

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

可以看到使用很正常,能正常注入使用: 

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

接下來我們換成使用  @Resource

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

是的,@Resource也是用來玩注入的,目的就是讓我們能用到某些bean,調用測試:

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

兩個注解在   一個業務接口隻對應一個業務實作類   場景下, 用于注入對象都是很ok的。

(那麼他們是不是就是來源地不同,其餘根本沒差別啊? 不急,繼續往下)

模拟場景 二

一個業務接口 對應  兩個或多個業務實作類

也就是我們再次加上一個 UserServiceNewImpl  業務實作類:

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

這時候,就是有兩個業務實作類都實作了 UserService接口:

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

這時候,我們繼續 在測試的Controller裡面  使用 @Autowired   :

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

跑起來項目發現已經報錯了:

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

看到報錯資訊裡面非常貼心;

1. 告訴我們 ,在MyTestController裡面, 需要注入一個UserService (實作類), 但是卻發現了兩個這種類型的bean。

2. 提供解決思路, 告訴我們可以使用@Primay注解 告訴哪一個是優先注入的,或者 使用@Qualifier 指定一下 需要注入哪個。

原由:

 @Autowired   是根據 類型 (byType)注入的  ,然後在找到type類型的bean時,如果發現有異常(不唯一等),會再去根據name去找bean注入。

而我們使用方式代碼寫的是:

@Autowired
    UserService userService;      

因為兩個實作類bean都實作了UserService ,那肯定找到兩個了,也就是有異常了,然後name我們寫的是userService(實際兩個業務實作類我們用@Service丢到spring容器裡面預設名字是首字母小寫userServiceImpl,userServiceNewImpl),根本沒有userService這個東東。

ps: @Autowired的對象是通過接口的話,spring就預設會去使用jdk動态代理,jdk動态代理隻能對實作了接口的類生成代理,而不是針對實作類。 (既然已經提到了jdk動态代理,悄悄地說我們是不是可以改成直接注入實作類,是不是就解決了? 這個留給你們去敲一下代碼,這篇避免混淆,我不展示。)

那麼怎麼解決?

我們常配合 @Qualifier 注解去使用 ,指定一下 根據别人去注入。

也就是這樣:

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘
Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

那麼這樣,在這種 一個業務接口 對應  兩個或多個業務實作類  的場景,調用起來就沒啥問題了:

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘
Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

是以到這你應該清楚記住了一點 :  @Autowired   是根據 類型 (byType)注入的 , 然後當找到type類型的bean時,如果發現有異常(不唯一等),會再去根據name去找bean注入。

ps :

是以你遵循@Autowired 的玩法,寫成這樣 ,也是能解決的:

@Autowired
UserService userServiceImpl;      

緊接着我們換成使用  @Resource

我們先把起别名的删掉,恢複到 2個 實作類 都實作一個業務接口的場景:

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

然後在測試的Controller裡面  使用  @Resource

可以看到項目跑起來也一樣報錯了,也是說注入 UserServcie的時候,發現了2個實作類:

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

咋一看,裡面也有spring的事兒?

聽我給你慢慢剖析:

原由:

@Resource 預設是 根據 名字(byName)注入的 。

而且 @Resource 其實提供了 name 和 type 屬性值設定。

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

但是如果使用的時候,跟上文一樣啥都沒有指定,那麼就是先byName 預設方式去找(userService):

@Resource
    UserService userService;      

發現根本沒有這個userService, 因為我們 注入到bean容器裡面 是 這兩個玩意(@Servcie):

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

而且咱們使用@Servcie 注入這倆玩意沒有起别名,那麼就是預設 首字母變小寫 當做注入的bean名字。

那麼回到 @Resource ,它根據可靠資訊 name 名稱 ( userService  ),找不到bean;

那麼就會根據 type  類型 (UserService) 去spring容器裡面找找,有沒有這種類型的bean;

結果發現了 兩個類型都是 UserService 的 兩個倒黴孩子  userServiceImpl,userServiceNewImpl ;

是以就報錯咯。

怎麼解決這種場景下使用  @Resource  ?

看完我的剖析,你應該明白, @Resource  人家預設 byName 去找bean ,然後還提供name 和type 一起設定或者單一設定。

也就是說,這個@Resource   已經做得很到位了。

簡單解決,設定名字咯,剛剛說了 我們使用@Service 注入實作類bean的時候,沒有特意指定名稱,那麼就是首字母小寫當做了bean的名稱,是以我們使用@Resource 也指定設定一下name:

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

然後把項目跑起來,調用測試下:

Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘
Springboot @Autowired 和 @Resource 我的剖析,你看完就不會忘

沒錯,恭喜這個倒黴的孩子能正常被找到,

也在這恭喜閱讀完文章的你,你無疑已經了解明白了@Autowired和 @Resource 這兩玩意的差別、作用、用法。

繼續閱讀