最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring中的@AliasFor標(biāo)簽的用法及說明

 更新時間:2026年03月16日 11:00:56   作者:叩丁狼  
Spring框架中的@AliasFor標(biāo)簽用于定義注解屬性的別名,使得在同一個注解中可以使用相同的屬性值,從而提高代碼的可讀性和可維護(hù)性

在Spring的眾多注解中,經(jīng)常會發(fā)現(xiàn)很多注解的不同屬性起著相同的作用,比如@RequestMapping的value屬性和path屬性,這就需要做一些基本的限制,比如value和path的值不能沖突,比如任意設(shè)置value或者設(shè)置path屬性的值,都能夠通過另一個屬性來獲取值等等。為了統(tǒng)一處理這些情況,Spring創(chuàng)建了@AliasFor標(biāo)簽。

使用

@AliasFor標(biāo)簽有幾種使用方式。

1,在同一個注解內(nèi)顯示使用;比如在@RequestMapping中的使用示例:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    //...
}

又比如@ContextConfiguration注解中的value和locations屬性:

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ContextConfiguration {
    @AliasFor("locations")
    String[] value() default {};

    @AliasFor("value")
    String[] locations() default {};
    //...
}

在同一個注解中成對使用即可,比如示例代碼中,value和path就是互為別名。但是要注意一點,@AliasFor標(biāo)簽有一些使用限制,但是這應(yīng)該能想到的,比如要求互為別名的屬性屬性值類型,默認(rèn)值,都是相同的,互為別名的注解必須成對出現(xiàn),比如value屬性添加了@AliasFor(“path”),那么path屬性就必須添加@AliasFor(“value”),另外還有一點,互為別名的屬性必須定義默認(rèn)值。

那么如果違反了別名的定義,在使用過程中就會報錯,我們來做個簡單測試:

@ContextConfiguration(value = "aa.xml", locations = "bb.xml")
public class AnnotationUtilsTest {
    @Test
    public void testAliasfor() {
        ContextConfiguration cc = AnnotationUtils.findAnnotation(getClass(),
                ContextConfiguration.class);
        System.out.println(
                StringUtils.arrayToCommaDelimitedString(cc.locations()));
        System.out.println(StringUtils.arrayToCommaDelimitedString(cc.value()));
    }
}

執(zhí)行測試,報錯;value和locations互為別名,不能同時設(shè)置;

稍微調(diào)整一下代碼:

@MyAnnotation
@ContextConfiguration(value = "aa.xml", locations = "aa.xml")
public class AnnotationUtilsTest {

或者

@MyAnnotation
@ContextConfiguration(value = "aa.xml")
public class AnnotationUtilsTest {

運(yùn)行測試,均打印出:

aa.xml

aa.xml

2,顯示的覆蓋元注解中的屬性;

先來看一段代碼:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AopConfig.class)
public class AopUtilsTest {

這段代碼是一個非常熟悉的基于JavaConfig的Spring測試代碼;假如現(xiàn)在我有個癖好,我覺得每次寫@ContextConfiguration(classes = AopConfig.class)太麻煩了,我想寫得簡單一點,我就可以定義一個這樣的標(biāo)簽:

@Retention(RetentionPolicy.RUNTIME)
@ContextConfiguration
public @interface STC {

    @AliasFor(value = "classes", annotation = ContextConfiguration.class)
    Class<?>[] cs() default {};

}

1,因為@ContextConfiguration注解本身被定義為@Inherited的,所以我們的STC注解即可理解為繼承了@ContextConfiguration注解;

2,我覺得classes屬性太長了,所以我創(chuàng)建了一個cs屬性,為了讓這個屬性等同于@ContextConfiguration屬性中的classes屬性,我使用了@AliasFor標(biāo)簽,分別設(shè)置了value(即作為哪個屬性的別名)和annotation(即作為哪個注解);

使用我們的STC:

@RunWith(SpringJUnit4ClassRunner.class)
@STC(cs = AopConfig.class)
public class AopUtilsTest {

    @Autowired
    private IEmployeeService service;

正常運(yùn)行;

這就是@AliasFor標(biāo)簽的第二種用法,顯示的為元注解中的屬性起別名;這時候也有一些限制,比如屬性類型,屬性默認(rèn)值必須相同;當(dāng)然,在這種使用情況下,@AliasFor只能為作為當(dāng)前注解的元注解起別名;

3,在一個注解中隱式聲明別名;

這種使用方式和第二種使用方式比較相似,我們直接使用Spring官方文檔的例子:

 @ContextConfiguration
 public @interface MyTestConfig {

    @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    String[] value() default {};

    @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    String[] groovyScripts() default {};

    @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    String[] xmlFiles() default {};
 }

可以看到,在MyTestConfig注解中,為value,groovyScripts,xmlFiles都定義了別名@AliasFor(annotation = ContextConfiguration.class, attribute = “locations”),所以,其實在這個注解中,value、groovyScripts和xmlFiles也互為別名,這個就是所謂的在統(tǒng)一注解中的隱式別名方式;

4,別名的傳遞;

@AliasFor注解是允許別名之間的傳遞的,簡單理解,如果A是B的別名,并且B是C的別名,那么A是C的別名;

我們看一個例子:

 @MyTestConfig
 public @interface GroovyOrXmlTestConfig {

    @AliasFor(annotation = MyTestConfig.class, attribute = "groovyScripts")
    String[] groovy() default {};

    @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    String[] xml() default {};
 }

1,GroovyOrXmlTestConfig把 @MyTestConfig(參考上一個案例)作為元注解;

2,定義了groovy屬性,并作為MyTestConfig中的groovyScripts屬性的別名;

3,定義了xml屬性,并作為ContextConfiguration中的locations屬性的別名;

4,因為MyTestConfig中的groovyScripts屬性本身就是ContextConfiguration中的locations屬性的別名;所以xml屬性和groovy屬性也互為別名;

這個就是別名的傳遞性;

原理

明白@AliasFor標(biāo)簽的使用方式,我們簡單來看看@AliasFor標(biāo)簽的使用原理;

首先來看看該標(biāo)簽的定義:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AliasFor {

    @AliasFor("attribute")
    String value() default "";

    @AliasFor("value")
    String attribute() default "";

    Class<? extends Annotation> annotation() default Annotation.class;

}

可以看到,@AliasFor標(biāo)簽自己就使用了自己,為value屬性添加了attribute屬性作為別名;

那么就把這個注解放在我們需要的地方就可以了么?真就這么簡單么?我們來做一個例子:

1,創(chuàng)建一個注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {

    @AliasFor("alias")
    String value() default "";

    @AliasFor("value")
    String alias() default "";

}

在該注解中,我們讓alias和value屬性互為別名;

2,完成測試類:

@MyAnnotation(value = "aa", alias = "bb")
public class AnnotationUtilsTest {

    @Test
    public void testAliasfor2() {
        MyAnnotation ann = getClass().getAnnotation(MyAnnotation.class);
        System.out.println(ann.value());
        System.out.println(ann.alias());
    }
}

我們將MyAnnotation放在AnnotationUtilsTest上,可以看到,我們故意將value和alias值設(shè)置為不一樣的,然后在測試代碼中分別獲取value()和alias()的值,結(jié)果打?。?/p>

aa

bb

WTF?和預(yù)期的不一樣?原因很簡單,AliasFor是Spring定義的標(biāo)簽,要使用他,只能讓Spring來處理,修改測試代碼:

@MyAnnotation(value = "aa", alias = "bb")
public class AnnotationUtilsTest {

    @Test
    public void testAliasfor3() {
        MyAnnotation ann = AnnotationUtils.findAnnotation(getClass(),
                MyAnnotation.class);
        System.out.println(ann.value());
        System.out.println(ann.alias());
    }
}

這次我們使用Spring的AnnotationUtils工具類的findAnnotation方法來獲取標(biāo)簽,然后再次打印value()和alias()值:

如愿報錯;所以,使用@AliasFor最需要注意一點的,就是只能使用Spring的AnnotationUtils工具類來獲??;

而真正在起作用的,是AnnotationUtils工具類中的<A extends Annotation> A synthesizeAnnotation(A annotation, AnnotatedElement annotatedElement)方法;

這個方法傳入注解對象,和這個注解對象所在的類型,返回一個經(jīng)過處理(這個處理就主要是用于處理@AliasFor標(biāo)簽)之后的注解對象,簡單說,這個方法就是把A注解對象—-(經(jīng)過處理)——>支持AliasFor的A注解對象,我們來看看其中的關(guān)鍵代碼:

DefaultAnnotationAttributeExtractor attributeExtractor =
    new DefaultAnnotationAttributeExtractor(annotation, annotatedElement);
InvocationHandler handler = 
    new SynthesizedAnnotationInvocationHandler(attributeExtractor);
return (A) Proxy.newProxyInstance(annotation.getClass().getClassLoader(),
    new Class<?>[] {(Class<A>) annotationType, SynthesizedAnnotation.class}, handler);

可以看到,本質(zhì)原理就是使用了AOP來對A注解對象做了次動態(tài)代理,而用于處理代理的對象為SynthesizedAnnotationInvocationHandler;我們來看看SynthesizedAnnotationInvocationHandler中的重要處理代碼:

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (isEqualsMethod(method)) {
        return annotationEquals(args[0]);
    }
    if (isHashCodeMethod(method)) {
        return annotationHashCode();
    }
    if (isToStringMethod(method)) {
        return annotationToString();
    }
    if (isAnnotationTypeMethod(method)) {
        return annotationType();
    }
    if (!isAttributeMethod(method)) {
        String msg = String.format("Method [%s] is unsupported for synthesized annotation type [%s]", method,
            annotationType());
        throw new AnnotationConfigurationException(msg);
    }
    return getAttributeValue(method);
}

在invoke(即攔截方法中,這個攔截方法就是在注解中獲取屬性值的方法,不要忘了,注解的屬性實際上定義為接口的方法),其次判斷,如果當(dāng)前執(zhí)行的方法不是equals、hashCode、toString、或者屬性是另外的注解,或者不是屬性方法,之外的方法(這些方法就是要處理的目標(biāo)屬性),都調(diào)用了getAttributeValue方法,所以我們又跟蹤到getAttributeValue方法的重要代碼:

String attributeName = attributeMethod.getName();
        Object value = this.valueCache.get(attributeName);
        if (value == null) {
            value = this.attributeExtractor.getAttributeValue(attributeMethod);

這里我們重點關(guān)注的是如果沒有緩存到值(這個先不用管),直接調(diào)用attributeExtractor.getAttributeValue方法獲取屬性值,那么,很容易猜到,如果屬性有@AliasFor注解,就應(yīng)該是這個方法在處理;那我們來看看這個方法又在做什么事情:

attributeExtractor是一個AnnotationAttributeExtractor類型,這個對象是在構(gòu)造SynthesizedAnnotationInvocationHandler時傳入的,默認(rèn)是一個DefaultAnnotationAttributeExtractor對象;而DefaultAnnotationAttributeExtractor是繼承AbstractAliasAwareAnnotationAttributeExtractor,看名字,真正的處理AliasFor標(biāo)簽的動作,應(yīng)該就在這里面,于是繼續(xù)看代碼:

public final Object getAttributeValue(Method attributeMethod) {
        String attributeName = attributeMethod.getName();
        Object attributeValue = getRawAttributeValue(attributeMethod);

        List<String> aliasNames = this.attributeAliasMap.get(attributeName);
        if (aliasNames != null) {
            Object defaultValue = AnnotationUtils.getDefaultValue(getAnnotationType(), attributeName);
            for (String aliasName : aliasNames) {
                Object aliasValue = getRawAttributeValue(aliasName);

                if (!ObjectUtils.nullSafeEquals(attributeValue, aliasValue) &&
                        !ObjectUtils.nullSafeEquals(attributeValue, defaultValue) &&
                        !ObjectUtils.nullSafeEquals(aliasValue, defaultValue)) {
                    throw new AnnotationConfigurationException(...)
                }
                if (ObjectUtils.nullSafeEquals(attributeValue, defaultValue)) {
                    attributeValue = aliasValue;
                }
            }
        }

        return attributeValue;
    }

對原代碼做了些改造,但是我們能清晰的看到重點:

1,首先正常獲取當(dāng)前屬性的值;

2,List<String> aliasNames = this.attributeAliasMap.get(attributeName);得到所有的標(biāo)記為別名的屬性名稱;

3,Object aliasValue = getRawAttributeValue(aliasName);遍歷獲取所有別名屬性的值;

4,三個重要判斷,attributeValue、aliasValue、defaultValue相同,我們前面介紹的@AliasFor標(biāo)簽的傳遞性也是在這里體現(xiàn);如果不相同,直接拋出異常;否則正常返回屬性值;

至此,AliasFor的執(zhí)行過程分析完畢;

總結(jié)

類似@AliasFor這樣的注解,在Spring框架中比比皆是,而每一個這樣的細(xì)節(jié)的點,都值得我們?nèi)ンw會。

我們常常說Spring框架非常復(fù)雜,因為在每一個點的實現(xiàn),都要考慮很多健壯性和擴(kuò)展性的問題,這些,都是我們值得去研究的。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • JAVA常用API總結(jié)與說明

    JAVA常用API總結(jié)與說明

    這篇文章主要介紹了JAVA常用API總結(jié)與說明,包括JAVA線程常用API,JAVA隊列常用API,JAVA泛型集合算法常用API,JAVA并發(fā)常用API需要的朋友可以參考下
    2022-12-12
  • JAVA 泛型與通配符詳解從原理到實戰(zhàn)應(yīng)用

    JAVA 泛型與通配符詳解從原理到實戰(zhàn)應(yīng)用

    本章全面介紹了泛型的核心概念、設(shè)計初衷及三大使用方式(泛型類、泛型接口、泛型方法),重點講解了泛型的擦除機(jī)制和通配符的靈活運(yùn)用,強(qiáng)調(diào)了泛型在編譯期類型安全和運(yùn)行時類型擦除的優(yōu)勢,感興趣的朋友跟隨小編一起看看吧
    2026-03-03
  • java實現(xiàn)簡單的學(xué)生信息管理系統(tǒng)代碼實例

    java實現(xiàn)簡單的學(xué)生信息管理系統(tǒng)代碼實例

    這篇文章主要介紹了java實現(xiàn)簡單的學(xué)生信息管理系統(tǒng),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • SpringBoot2.6.x升級后循環(huán)依賴及Swagger無法使用問題

    SpringBoot2.6.x升級后循環(huán)依賴及Swagger無法使用問題

    這篇文章主要為大家介紹了SpringBoot2.6.x升級后循環(huán)依賴及Swagger無法使用問題,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Java?將list集合數(shù)據(jù)按照時間字段排序的方法

    Java?將list集合數(shù)據(jù)按照時間字段排序的方法

    這篇文章主要介紹了Java?將list集合數(shù)據(jù)按照時間字段排序,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03
  • 使用BufferedReader讀取TXT文件中數(shù)值,并輸出最大值

    使用BufferedReader讀取TXT文件中數(shù)值,并輸出最大值

    這篇文章主要介紹了使用BufferedReader讀取TXT文件中數(shù)值,并輸出最大值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Spring Boot 整合 Redis示例代碼步驟詳解

    Spring Boot 整合 Redis示例代碼步驟詳解

    本文介紹了如何在SpringBoot應(yīng)用中整合Redis,并通過示例代碼展示了具體實現(xiàn)步驟,包括添加依賴、配置連接信息、創(chuàng)建操作服務(wù)類、使用RedisTemplate或ReactiveRedisTemplate以及測試功能,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • Spring Task 動態(tài)修改任務(wù)執(zhí)行計劃cron方式

    Spring Task 動態(tài)修改任務(wù)執(zhí)行計劃cron方式

    這篇文章主要介紹了Spring Task 動態(tài)修改任務(wù)執(zhí)行計劃cron方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 對Java中傳值調(diào)用的理解分析

    對Java中傳值調(diào)用的理解分析

    這篇文章主要介紹了對Java中傳值調(diào)用的理解分析,通過分析對比,較為深入的分析了Java中傳值調(diào)用的原理與用法,需要的朋友可以參考下
    2015-01-01
  • SpringBoot集成RedisTemplate的實現(xiàn)示例

    SpringBoot集成RedisTemplate的實現(xiàn)示例

    本文主要介紹了SpringBoot集成RedisTemplate的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-09-09

最新評論

兖州市| 凤阳县| 会昌县| 罗城| 汾阳市| 栖霞市| 团风县| 青浦区| 日喀则市| 阳江市| 苗栗县| 年辖:市辖区| 柯坪县| 高淳县| 元江| 乐山市| 阿坝县| 盈江县| 班玛县| 榕江县| 民权县| 湘西| 二连浩特市| 高密市| 新津县| 陆川县| 芜湖市| 无为县| 嘉黎县| 大连市| 屏东县| 温宿县| 凯里市| 贺兰县| 五峰| 佛教| 伊通| 纳雍县| 比如县| 自贡市| 九江市|