Java @Autowired注解底層原理詳細(xì)分析
1.概念
@Autowired 是 Spring 提供的注解,默認(rèn)的注入方式為 byType (按類(lèi)型自動(dòng)注入);@Autowired 注釋?zhuān)梢詫?duì)類(lèi)成員變量、方法及構(gòu)造函數(shù)進(jìn)行標(biāo)注,完成自動(dòng)裝配的工作;通過(guò) @Autowired的使用來(lái)消除 set ,get方法。
2.注入數(shù)據(jù)的注解
@Value
含義:通過(guò)set方式注入基本類(lèi)型與String,set方法可以省略
語(yǔ)法:@Value("數(shù)據(jù)")/@Value("${key}")
位置:修飾屬性,set方法
注意:如果動(dòng)態(tài)獲取必須指定加載資源文件 <context:property-placeholderlocation="classpath:msg.properties"> </context:property-placeholder>
@Autowired
替換:autowire屬性,自動(dòng)裝配(按照類(lèi)型裝配,通過(guò)set方法,且方法可以省略)
位置:修飾屬性,set方法
語(yǔ)法:@Autowired(required="true")
注意:
1.如果容器中沒(méi)有一個(gè)可以與之匹配且required屬性為true則會(huì)報(bào)異常
NoSuchBeanDefinitionException
2.如果容器中有多個(gè)可以類(lèi)型可以與之匹配,則自動(dòng)切換為按照名稱(chēng)裝配
3.如果名稱(chēng)也沒(méi)有匹配,則報(bào)異常NoUniqueBeanDefinitionException
3.@Autowired注解是如何實(shí)現(xiàn)的
@Autowired注解在spring源代碼里的定義:
package org.springframework.beans.factory.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { boolean required() default true; }
通過(guò)代碼看到Autowired注解可以應(yīng)用在構(gòu)造方法,普通方法,參數(shù),字段,以及注解這五種類(lèi)型的地方,它的保留策略是在運(yùn)行時(shí)。
在Spring源代碼當(dāng)中,Autowired注解位于包org.springframework.beans.factory.annotation
之中,實(shí)現(xiàn)邏輯位于類(lèi):AutowiredAnnotationBeanPostProcessor
之中。
核心處理代碼如下:
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>(); Class<?> targetClass = clazz;//需要處理的目標(biāo)類(lèi) do { final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>(); /*通過(guò)反射獲取該類(lèi)所有的字段,并遍歷每一個(gè)字段,并通過(guò)方法findAutowiredAnnotation遍歷每一個(gè)字段的所用注解,并如果用autowired修飾了,則返回auotowired相關(guān)屬性*/ ReflectionUtils.doWithLocalFields(targetClass, field -> { AnnotationAttributes ann = findAutowiredAnnotation(field); if (ann != null) {//校驗(yàn)autowired注解是否用在了static方法上 if (Modifier.isStatic(field.getModifiers())) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation is not supported on static fields: " + field); } return; }//判斷是否指定了required boolean required = determineRequiredStatus(ann); currElements.add(new AutowiredFieldElement(field, required)); } }); //和上面一樣的邏輯,但是是通過(guò)反射處理類(lèi)的method ReflectionUtils.doWithLocalMethods(targetClass, method -> { Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { return; } AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod); if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { if (Modifier.isStatic(method.getModifiers())) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation is not supported on static methods: " + method); } return; } if (method.getParameterCount() == 0) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation should only be used on methods with parameters: " + method); } } boolean required = determineRequiredStatus(ann); PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); currElements.add(new AutowiredMethodElement(method, required, pd)); } }); //用@Autowired修飾的注解可能不止一個(gè),因此都加在currElements這個(gè)容器里面,一起處理 elements.addAll(0, currElements); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return new InjectionMetadata(clazz, elements); }
最后這個(gè)方法返回的就是包含所有帶有autowire注解修飾的一個(gè)InjectionMetadata集合。這個(gè)類(lèi)由兩部分組成:
public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) { this.targetClass = targetClass; this.injectedElements = elements; }
一是處理的目標(biāo)類(lèi),二就是上述方法獲取到的所以elements集合。
有了目標(biāo)類(lèi),與所有需要注入的元素集合之后,就可以實(shí)現(xiàn)autowired的依賴(lài)注入邏輯了,實(shí)現(xiàn)的方法如下:
@Override public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException { InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); } catch (BeanCreationException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); } return pvs; }
它調(diào)用的方法是InjectionMetadata中定義的inject方法,如下
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Collection<InjectedElement> checkedElements = this.checkedElements; Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements); if (!elementsToIterate.isEmpty()) { for (InjectedElement element : elementsToIterate) { if (logger.isTraceEnabled()) { logger.trace("Processing injected element of bean '" + beanName + "': " + element); } element.inject(target, beanName, pvs); } } }
其邏輯就是遍歷,然后調(diào)用inject方法,inject方法其實(shí)現(xiàn)邏輯如下:
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable { if (this.isField) { Field field = (Field) this.member; ReflectionUtils.makeAccessible(field); field.set(target, getResourceToInject(target, requestingBeanName)); } else { if (checkPropertySkipping(pvs)) { return; } try { Method method = (Method) this.member; ReflectionUtils.makeAccessible(method); method.invoke(target, getResourceToInject(target, requestingBeanName)); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } }
inject也使用了反射技術(shù)并且依然是分成字段和方法去處理的。
到此這篇關(guān)于Java @Autowired注解底層原理詳細(xì)分析的文章就介紹到這了,更多相關(guān)Java @Autowired注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
nacos單機(jī)版啟動(dòng)失敗問(wèn)題以及解決
這篇文章主要介紹了nacos單機(jī)版啟動(dòng)失敗問(wèn)題以及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07Java中字符串轉(zhuǎn)int數(shù)據(jù)類(lèi)型的三種方式
這篇文章主要介紹了Java中字符串轉(zhuǎn)int數(shù)據(jù)類(lèi)型的三種方式,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03從lombok的val和var到JDK的var關(guān)鍵字方式
這篇文章主要介紹了從lombok的val和var到JDK的var關(guān)鍵字方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05使用SpringBoot動(dòng)態(tài)切換數(shù)據(jù)源的實(shí)現(xiàn)方式
在我們企業(yè)項(xiàng)目開(kāi)發(fā)的過(guò)程中,有的時(shí)候,一個(gè)項(xiàng)目需要在運(yùn)行時(shí),根據(jù)某種條件選擇使用哪個(gè)數(shù)據(jù)源,那么此時(shí)該怎么進(jìn)行動(dòng)態(tài)切換呢,本文給大家例舉一種常見(jiàn)的實(shí)現(xiàn)方式,文中有詳細(xì)的實(shí)現(xiàn)步驟,需要的朋友可以參考下2023-12-12解決spring @ControllerAdvice處理異常無(wú)法正確匹配自定義異常
這篇文章主要介紹了解決spring @ControllerAdvice處理異常無(wú)法正確匹配自定義異常的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06SpringBoot集成Quartz實(shí)現(xiàn)定時(shí)任務(wù)的方法
Quartz是一個(gè)定時(shí)任務(wù)框架,其他介紹網(wǎng)上也很詳盡。這里要介紹一下Quartz里的幾個(gè)非常核心的接口。通過(guò)實(shí)例代碼給大家講解SpringBoot集成Quartz實(shí)現(xiàn)定時(shí)任務(wù)的方法,感興趣的朋友一起看看吧2020-05-05springBoot解決static和@Component遇到的bug
這篇文章主要介紹了springBoot解決static和@Component遇到的bug,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02Java中List轉(zhuǎn)Map的幾種常見(jiàn)方式與對(duì)比
JavaList轉(zhuǎn)Map是一個(gè)非常常用的技術(shù),對(duì)于Java開(kāi)發(fā)人員來(lái)講,掌握該技術(shù)可以幫助我們更加高效地操作List集合中的對(duì)象,這篇文章主要給大家介紹了關(guān)于Java中List轉(zhuǎn)Map的幾種常見(jiàn)方式與對(duì)比的相關(guān)資料,需要的朋友可以參考下2024-02-02