前言
@Autowired 和 @Resource
這兩個注解大家想必都有在項目裡面出現過,但是真的清楚這倆玩意的用法或者說是差別麼?
一直用的都是 @Autowired ?
别人代碼用什麼就copy用什麼,反正他沒錯,俺也不會錯?
它們都是一樣的作用?隻是名字不一樣而已?
如果你存在以上這些疑問,那麼你看這篇文章必賺! 上車!
如果你不存在以上這些疑問,那麼你看這篇文章也不虧!
正文
跟着我 了解下 @Autowired 和 @Resource 這兩位兄台
1.看看他們從哪裡來?
@Autowired :
@Resource :
從這我們可以知道,
@Autowired 是一個 spring 的注解
@Resource
2.他們的作用是什麼?
既然說到作用,那按照咱們的風格,肯定是結合執行個體介紹,我們從不光紙上談兵。
(我知道你知道他們是用于注入的,但是你可能隻是知道,你不徹底了解)
模拟場景 一
一個業務接口隻對應一個業務實作類:
一個 UserService 接口:
一個UserServiceImpl 接口實作類 :
首先我們 在測試的Controller裡面 使用 @Autowired :
調用測試:
可以看到使用很正常,能正常注入使用:
接下來我們換成使用 @Resource
是的,@Resource也是用來玩注入的,目的就是讓我們能用到某些bean,調用測試:
兩個注解在 一個業務接口隻對應一個業務實作類 場景下, 用于注入對象都是很ok的。
(那麼他們是不是就是來源地不同,其餘根本沒差別啊? 不急,繼續往下)
模拟場景 二
一個業務接口 對應 兩個或多個業務實作類
也就是我們再次加上一個 UserServiceNewImpl 業務實作類:
這時候,就是有兩個業務實作類都實作了 UserService接口:
這時候,我們繼續 在測試的Controller裡面 使用 @Autowired :
跑起來項目發現已經報錯了:
看到報錯資訊裡面非常貼心;
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 注解去使用 ,指定一下 根據别人去注入。
也就是這樣:
那麼這樣,在這種 一個業務接口 對應 兩個或多個業務實作類 的場景,調用起來就沒啥問題了:
是以到這你應該清楚記住了一點 : @Autowired 是根據 類型 (byType)注入的 , 然後當找到type類型的bean時,如果發現有異常(不唯一等),會再去根據name去找bean注入。
ps :
是以你遵循@Autowired 的玩法,寫成這樣 ,也是能解決的:
@Autowired
UserService userServiceImpl;
緊接着我們換成使用 @Resource
我們先把起别名的删掉,恢複到 2個 實作類 都實作一個業務接口的場景:
然後在測試的Controller裡面 使用 @Resource
可以看到項目跑起來也一樣報錯了,也是說注入 UserServcie的時候,發現了2個實作類:
咋一看,裡面也有spring的事兒?
聽我給你慢慢剖析:
原由:
@Resource 預設是 根據 名字(byName)注入的 。
而且 @Resource 其實提供了 name 和 type 屬性值設定。
但是如果使用的時候,跟上文一樣啥都沒有指定,那麼就是先byName 預設方式去找(userService):
@Resource
UserService userService;
發現根本沒有這個userService, 因為我們 注入到bean容器裡面 是 這兩個玩意(@Servcie):
而且咱們使用@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:
然後把項目跑起來,調用測試下:
沒錯,恭喜這個倒黴的孩子能正常被找到,
也在這恭喜閱讀完文章的你,你無疑已經了解明白了@Autowired和 @Resource 這兩玩意的差別、作用、用法。