Spring中@Autowired @Resource @Inject三個注解有什么區(qū)別
javax.annotation.Resource
jdk 內(nèi)置的,JSR-250 中的注解。
依賴注入通過 org.springframework.context.annotation.CommonAnnotationBeanPostProcessor 來處理。
org.springframework.beans.factory.annotation.Autowired org.springframework.beans.factory.annotation.Value
javax.inject.Inject
JSR-330 中的注解,作用同 @Autowired
依賴注入通過 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor 來處理。
org.springframework.beans.factory.annotation.Qualifier javax.inject.Qualifier
依賴注入通過 org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver 來處理。
@Autowired
spring 自帶的注解。
注入順序
按照 type 在 上下文中查找匹配的 bean
如果有多個 bean,按照 name 進行匹配
- 如果有 @Qualifier 注解,按照 @Qualifier 指定的 name 進行匹配
- 如果沒有,按照變量名進行匹配
匹配不到,報錯。因為 required 默認為 true,不想注入設(shè)置此 bean @Autowired(required=false)。
@Inject
在 spring 中,@Inject 和 @Autowired 相同。
@Inject 和 @Autowired 區(qū)別
@Inject 是 javaee 6 及以上版本包里的。
@Autowired 可以設(shè)置 required=false 而 @Inject 沒有這個屬性。
@Resource
有兩個重要的屬性,name 和 type,spring 將 name 屬性解析為 bean 的名字,type 解析為 bean 的類型。如果未指定 name,取變量名給 name 賦值。
CommonAnnotationBeanPostProcessor 中Resource 賦值源碼
/** * Class representing injection information about an annotated field * or setter method, supporting the @Resource annotation. */ private class ResourceElement extends LookupElement { private final boolean lazyLookup; public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) { super(member, pd); Resource resource = ae.getAnnotation(Resource.class); String resourceName = resource.name(); Class<?> resourceType = resource.type(); this.isDefaultName = !StringUtils.hasLength(resourceName); if (this.isDefaultName) { resourceName = this.member.getName(); if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) { resourceName = Introspector.decapitalize(resourceName.substring(3)); } } else if (embeddedValueResolver != null) { resourceName = embeddedValueResolver.resolveStringValue(resourceName); } if (Object.class != resourceType) { checkResourceType(resourceType); } else { // No resource type specified... check field/method. resourceType = getResourceType(); } this.name = (resourceName != null ? resourceName : ""); this.lookupType = resourceType; String lookupValue = resource.lookup(); this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName()); Lazy lazy = ae.getAnnotation(Lazy.class); this.lazyLookup = (lazy != null && lazy.value()); } @Override protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) { return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) : getResource(this, requestingBeanName)); } }
在變量名相同的情況下報錯
The bean could not be injected as a because it is a JDK dynamic proxy that implements:
指定了不同type無法解決問題,跟進源碼發(fā)現(xiàn)是 spring boot 把異常給處理了
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'productInit':
Injection of resource dependencies failed;
nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException:
Bean named 'example2ProductMapper' is expected to be of type 'com.alibaba.cloud.youxia.manager.ProductManager' but was actually of type 'com.sun.proxy.$Proxy47'
想到在 DefaultListableBeanFactory 中 beanDefinitionMap 按照名稱和 BeanDefinition 鍵值對的問題,名稱和注入的對象一一對應(yīng),不然就會出現(xiàn)不對應(yīng)的問題
注入規(guī)則
- 如果未指定 name,取變量名從上下文中查找名稱匹配的 bean 進行注入,找不到或者注入的變量名與類型無法對應(yīng)拋出異常。
- 如果指定了 name,則從上下文中查找名稱匹配的 bean 進行注入,找不到拋出異常。
- 如果指定了 type,有兩種情況
通過變量名從上下文中查找不到對應(yīng)的 bean,則通過 type則從上下文中查找類型匹配的 bean 進行注入,找不到拋出異常。
通過變量名從上下文中找到對應(yīng)的 bean但是注入的類型與無法與DefaultListableBeanFactory 中 beanDefinitionMap中通過變量名得到的 BeanDefinition 類型一致,拋出異常。
- 既沒有指定 name,又沒有指定 type,默認按照變量名進行注入。
- 如果同時指定了 name 和 type,從上下文中找到唯一匹配的 bean 進行注入,找不到拋出異常。
匹配順序為
變量名 → 指定的 name → 指定的 type
如果注入的 bean 變量名相同,但是類型不同,通過 name 指定是修改代碼量最小的辦法。
到此這篇關(guān)于Spring中@Autowired @Resource @Inject三個注解有什么區(qū)別的文章就介紹到這了,更多相關(guān)Spring @Autowired @Resource @Inject內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IDEA2022創(chuàng)建Maven Web項目教程(圖文)
本文主要介紹了IDEA2022創(chuàng)建Maven Web項目教程,文中通過圖文介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07SpringCloudAlibaba整合Feign實現(xiàn)遠程HTTP調(diào)用的簡單示例
這篇文章主要介紹了SpringCloudAlibaba 整合 Feign 實現(xiàn)遠程 HTTP 調(diào)用,文章中使用的是OpenFeign,是Spring社區(qū)開發(fā)的組件,需要的朋友可以參考下2021-09-09Security中的WebSecurityConfigurerAdapter詳解
這篇文章主要介紹了Security中的WebSecurityConfigurerAdapter詳解,今天我們要進一步的的學(xué)習(xí)如何自定義配置Spring?Security,本文結(jié)合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2023-07-07