Java注解機(jī)制之Spring自動(dòng)裝配實(shí)現(xiàn)原理詳解
Java中使用注解的情況主要在SpringMVC(Spring Boot等),注解實(shí)際上相當(dāng)于一種標(biāo)記語(yǔ)言,它允許你在運(yùn)行時(shí)動(dòng)態(tài)地對(duì)擁有該標(biāo)記的成員進(jìn)行操作。注意:spring框架默認(rèn)不支持自動(dòng)裝配的,要想使用自動(dòng)裝配需要修改spring配置文件中<bean>標(biāo)簽的autowire屬性。
自動(dòng)裝配屬性有6個(gè)值可選,分別代表不同的含義:
byName ->從Spring環(huán)境中獲取目標(biāo)對(duì)象時(shí),目標(biāo)對(duì)象中的屬性會(huì)根據(jù)名稱在整個(gè)Spring環(huán)境中查找<bean>標(biāo)簽的id屬性值。如果有相同的,那么獲取這個(gè)對(duì)象,實(shí)現(xiàn)關(guān)聯(lián)。整個(gè)Spring環(huán)境:表示所有的spring配置文件中查找,那么id不能有重復(fù)的。
byType ->從Spring環(huán)境中獲取目標(biāo)對(duì)象時(shí),目標(biāo)對(duì)象中的屬性會(huì)根據(jù)類(lèi)型在整個(gè)spring環(huán)境中查找<bean>標(biāo)簽的class屬性值。如果有相同的,那么獲取這個(gè)對(duì)象,實(shí)現(xiàn)關(guān)聯(lián)。
缺點(diǎn):如果存在多個(gè)相同類(lèi)型的bean對(duì)象,會(huì)出錯(cuò);如果屬性為單一類(lèi)型的數(shù)據(jù),那么查找到多個(gè)關(guān)聯(lián)對(duì)象會(huì)發(fā)生錯(cuò)誤;如果屬性為數(shù)組或集合(泛型)類(lèi)型,那么查找到多個(gè)關(guān)聯(lián)對(duì)象不會(huì)發(fā)生異常。
constructor ->使用構(gòu)造方法完成對(duì)象注入,其實(shí)也是根據(jù)構(gòu)造方法的參數(shù)類(lèi)型進(jìn)行對(duì)象查找,相當(dāng)于采用byType的方式。
autodetect ->自動(dòng)選擇:如果對(duì)象沒(méi)有無(wú)參數(shù)的構(gòu)造方法,那么自動(dòng)選擇constructor的自動(dòng)裝配方式進(jìn)行構(gòu)造注入。如果對(duì)象含有無(wú)參數(shù)的構(gòu)造方法,那么自動(dòng)選擇byType的自動(dòng)裝配方式進(jìn)行setter注入。
no ->不支持自動(dòng)裝配功能
default ->表示默認(rèn)采用上一級(jí)標(biāo)簽的自動(dòng)裝配的取值。如果存在多個(gè)配置文件的話,那么每一個(gè)配置文件的自動(dòng)裝配方式都是獨(dú)立的。
注解使用需要三個(gè)條件包括注解聲明,使用注解的元素,操作使用注解元素的代碼。第一步注解聲明,注解是一種類(lèi)型,自定義注解編寫(xiě)代碼如下:
package annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface AttachAnnotation { String paramValue() default "河北省"; // 參數(shù)名為"paramValue" 默認(rèn)值為"河北省" }
使用自定義注解元素,代碼如下:
package annotation; /** * @author 路人宅 */ public class AttachEmlement { // 普通 public void AttachDefault(String name){ System.out.println("歸屬:" + name); } // 使用注解并傳入?yún)?shù) @AttachAnnotation(paramValue="河北省") public void AttachAnnotation(String name){ System.out.println("歸屬:" + name); } // 使用注解并使用默認(rèn)參數(shù) @AttachAnnotation public void AttachAnnotationDefault(String name){ System.out.println("歸屬:" + name); } }
測(cè)試操作執(zhí)行main函數(shù),具體代碼如下:
package annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class AnnotionOperator { public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException { AttachEmlement element = new AttachEmlement(); // 初始化一個(gè)實(shí)例,用于方法調(diào)用 Method[] methods = AttachEmlement.class.getDeclaredMethods(); // 獲得所有方法 for (Method method : methods) { AttachAnnotation annotationTmp = null; if ((annotationTmp = method.getAnnotation(AttachAnnotation.class)) != null) method.invoke(element, annotationTmp.paramValue()); else method.invoke(element, "河南省"); } } }
執(zhí)行結(jié)果:
歸屬: 河南省
歸屬:河北省
歸屬:河北省
Spring為了方便自動(dòng)裝配進(jìn)行操作有兩種方式:繼承org.springframework.web.context.support.SpringBeanAutowiringSupport類(lèi)或者添加@Component/@Controller等注解并在Spring配置文件里聲明context:component-scan元素配置。
1) 繼承方式實(shí)現(xiàn)自動(dòng)裝配,查看Spring3.1.1源代碼會(huì)發(fā)現(xiàn)SpringBeanAutowiringSupport類(lèi)中有如下代碼:
/** * This constructor performs injection on this instance, * based on the current web application context. * Intended for use as a base class. * @see #processInjectionBasedOnCurrentContext */ public SpringBeanAutowiringSupport() { processInjectionBasedOnCurrentContext(this); }
分析:Java在實(shí)例化構(gòu)造時(shí)會(huì)調(diào)用默認(rèn)父類(lèi)無(wú)參構(gòu)造方法,而Spring就是通過(guò)這一點(diǎn),讓操作元素代碼執(zhí)行的。
2) 通過(guò)注解方式的也和上述理論相似,值得注意的是注解自動(dòng)裝配無(wú)需完成注入setter*,查看Spring3.1.1源碼注解調(diào)用順序得出:
org.springframework.web.context.support.SpringBeanAutowiringSupport#SpringBeanAutowiringSupport=>
org.springframework.web.context.support.SpringBeanAutowiringSupport#processInjectionBasedOnCurrentContext=>
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#processInjection=>
org.springframework.beans.factory.annotation.InjectionMetadata#Injection,查看inject方法源代碼如下:
/** * Either this or {@link #getResourceToInject} needs to be overridden. */ protected void inject(Object target, String requestingBeanName, 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(); } } }
分析:通過(guò)上述源碼Spring自動(dòng)裝配是通過(guò)反射機(jī)制來(lái)實(shí)現(xiàn)的。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java注解之Retention、Documented、Inherited介紹
- java教程之java注解annotation使用方法
- 5分鐘搞懂java注解@Annotation的具體使用
- Java注解Annotation與自定義注解詳解
- Java注解@Transactional事務(wù)類(lèi)內(nèi)調(diào)用不生效問(wèn)題及解決辦法
- 基于Java注解(Annotation)的自定義注解入門(mén)介紹
- 詳解Java注解教程及自定義注解
- 創(chuàng)建自定義的Java注解類(lèi)的方法
- 深入理解Java注解類(lèi)型(@Annotation)
- 輕松掌握J(rèn)ava注解,讓編程更智能、更優(yōu)雅
相關(guān)文章
SpringMVC?RESTFul實(shí)現(xiàn)列表功能
這篇文章主要為大家介紹了SpringMVC?RESTFul實(shí)現(xiàn)列表功能詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05java?Date和SimpleDateFormat時(shí)間類(lèi)詳解
這篇文章主要介紹了java?Date和SimpleDateFormat時(shí)間類(lèi)詳解,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08基于Springboot2.3訪問(wèn)本地路徑下靜態(tài)資源的方法(解決報(bào)錯(cuò):Not allowed to load local
這篇文章主要介紹了基于Springboot2.3訪問(wèn)本地路徑下靜態(tài)資源的方法(解決報(bào)錯(cuò):Not allowed to load local resource),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08java 中遍歷取值異常(Hashtable Enumerator)解決辦法
這篇文章主要介紹了java 中遍歷取值異常(Hashtable Enumerator)解決辦法的相關(guān)資料,用迭代器取值時(shí)拋出的異常:java.util.NoSuchElementException: Hashtable Enumerator ,需要的朋友可以參考下2017-08-08利用java反射機(jī)制實(shí)現(xiàn)自動(dòng)調(diào)用類(lèi)的簡(jiǎn)單方法
下面小編就為大家?guī)?lái)一篇利用java反射機(jī)制實(shí)現(xiàn)自動(dòng)調(diào)用類(lèi)的簡(jiǎn)單方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08