Java注解機(jī)制之Spring自動裝配實(shí)現(xiàn)原理詳解
Java中使用注解的情況主要在SpringMVC(Spring Boot等),注解實(shí)際上相當(dāng)于一種標(biāo)記語言,它允許你在運(yùn)行時動態(tài)地對擁有該標(biāo)記的成員進(jìn)行操作。注意:spring框架默認(rèn)不支持自動裝配的,要想使用自動裝配需要修改spring配置文件中<bean>標(biāo)簽的autowire屬性。
自動裝配屬性有6個值可選,分別代表不同的含義:
byName ->從Spring環(huán)境中獲取目標(biāo)對象時,目標(biāo)對象中的屬性會根據(jù)名稱在整個Spring環(huán)境中查找<bean>標(biāo)簽的id屬性值。如果有相同的,那么獲取這個對象,實(shí)現(xiàn)關(guān)聯(lián)。整個Spring環(huán)境:表示所有的spring配置文件中查找,那么id不能有重復(fù)的。
byType ->從Spring環(huán)境中獲取目標(biāo)對象時,目標(biāo)對象中的屬性會根據(jù)類型在整個spring環(huán)境中查找<bean>標(biāo)簽的class屬性值。如果有相同的,那么獲取這個對象,實(shí)現(xiàn)關(guān)聯(lián)。
缺點(diǎn):如果存在多個相同類型的bean對象,會出錯;如果屬性為單一類型的數(shù)據(jù),那么查找到多個關(guān)聯(lián)對象會發(fā)生錯誤;如果屬性為數(shù)組或集合(泛型)類型,那么查找到多個關(guān)聯(lián)對象不會發(fā)生異常。
constructor ->使用構(gòu)造方法完成對象注入,其實(shí)也是根據(jù)構(gòu)造方法的參數(shù)類型進(jìn)行對象查找,相當(dāng)于采用byType的方式。
autodetect ->自動選擇:如果對象沒有無參數(shù)的構(gòu)造方法,那么自動選擇constructor的自動裝配方式進(jìn)行構(gòu)造注入。如果對象含有無參數(shù)的構(gòu)造方法,那么自動選擇byType的自動裝配方式進(jìn)行setter注入。
no ->不支持自動裝配功能
default ->表示默認(rèn)采用上一級標(biāo)簽的自動裝配的取值。如果存在多個配置文件的話,那么每一個配置文件的自動裝配方式都是獨(dú)立的。
注解使用需要三個條件包括注解聲明,使用注解的元素,操作使用注解元素的代碼。第一步注解聲明,注解是一種類型,自定義注解編寫代碼如下:
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);
}
}
測試操作執(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(); // 初始化一個實(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為了方便自動裝配進(jìn)行操作有兩種方式:繼承org.springframework.web.context.support.SpringBeanAutowiringSupport類或者添加@Component/@Controller等注解并在Spring配置文件里聲明context:component-scan元素配置。
1) 繼承方式實(shí)現(xiàn)自動裝配,查看Spring3.1.1源代碼會發(fā)現(xiàn)SpringBeanAutowiringSupport類中有如下代碼:
/**
* 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)造時會調(diào)用默認(rèn)父類無參構(gòu)造方法,而Spring就是通過這一點(diǎn),讓操作元素代碼執(zhí)行的。
2) 通過注解方式的也和上述理論相似,值得注意的是注解自動裝配無需完成注入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();
}
}
}
分析:通過上述源碼Spring自動裝配是通過反射機(jī)制來實(shí)現(xiàn)的。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
java語言實(shí)現(xiàn)權(quán)重隨機(jī)算法完整實(shí)例
這篇文章主要介紹了java語言實(shí)現(xiàn)權(quán)重隨機(jī)算法完整實(shí)例,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-11-11
Java中數(shù)據(jù)轉(zhuǎn)換及字符串的“+”操作方法
本文主要介紹了Java中的數(shù)據(jù)類型轉(zhuǎn)換,包括隱式轉(zhuǎn)換和強(qiáng)制轉(zhuǎn)換,隱式轉(zhuǎn)換通常用于將范圍較小的數(shù)據(jù)類型轉(zhuǎn)換為范圍較大的數(shù)據(jù)類型,而強(qiáng)制轉(zhuǎn)換則是將范圍較大的數(shù)據(jù)類型轉(zhuǎn)換為范圍較小的數(shù)據(jù)類型,本文介紹Java中數(shù)據(jù)轉(zhuǎn)換以及字符串的“+”操作,感興趣的朋友一起看看吧2024-10-10
java正則表達(dá)式之Pattern與Matcher類詳解
這篇文章主要給大家介紹了關(guān)于java正則表達(dá)式之Pattern與Matcher類的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
基于Spring概念模型:PathMatcher 路徑匹配器
這篇文章主要介紹了Spring概念模型:PathMatcher 路徑匹配器,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
Java Agent入門學(xué)習(xí)之動態(tài)修改代碼
這篇文章主要給大家分享了Java Agent入門學(xué)習(xí)之動態(tài)修改代碼的相關(guān)資料,文中介紹的非常詳細(xì),對大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-07-07

