【spring】@AliasFor 使用规则

1. @AliasFor

@AliasFor是一个注解,用于为注解属性声明别名。

代码如下:它有两个属性value和attribute @AliasFor注解注释了自身,并且value和attribute互为别名:

@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;
}

2. 作用

2.1 AliasFor可以定义一个注解中的两个属性互为别名

如:

public @interface ComponentScan {
    @AliasFor("basePackages")
    String[] value() default {};
    
    @AliasFor("value")
    String[] basePackages() default {};
    
    boolean lazyInit() default false;
    ...
}

ComponentScan中的value和basePackages作用是一样的。

@ComponentScan("com.binecy")
public class SimpleAlias {

    public static void main(String[] args) {
        ComponentScan ann = AnnotationUtils.getAnnotation(SimpleAlias.class, ComponentScan.class);
        System.out.println(ann.value()[0]);
        System.out.println(ann.basePackages()[0]);
    }
}

结果都是com.binecy

有了AliasFor的好处是,如果我们只需要指定basePackages,可以使用value属性,并且省略value属性
@ComponentScan("com.binecy")

value可以省略,basePackages等价于value,因此,也可以省略,完整的用法是@ComponentScan(basePackages="com.binecy")

如果除了basePackages,还有其他属性,可以使用
@ComponentScan(basePackages = "com.binecy", lazyInit = true)
将value属性换成basePackages,更明确清晰。

2.2 跨注解的属性别名

@Component
public @interface Service {
    @AliasFor(annotation = Component.class)
    String value() default "";
}

@Service#value为@Component#value的别名,@Service#value的值可以映射到@Component#value。
(这里我们将@Service,@Component看做一种特殊的继承关系,@Component是父注解,@Service是子注解,@Service#value覆盖@Component#value)

demo:

package com.my.test;

import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

@Service("serviceAlias")
public class ServiceAlias {

    public static void main(String[] args) {
        //打印父Component.class,结果不为null,只是属性为null
        Component component = AnnotationUtils.getAnnotation(ServiceAlias.class, Component.class);
        System.out.println(component);

        //通过merge打印父Component.class,结果不为null,属性有值
        Component component2 = AnnotatedElementUtils.getMergedAnnotation(ServiceAlias.class, Component.class);
        System.out.println(component2);

        //打印Service.class自身,结果不为null,属性有值
        Service component3 = AnnotationUtils.getAnnotation(ServiceAlias.class, Service.class);
        System.out.println(component3);
        //打印不相关的Controller.class,结果为null
        Controller component4 = AnnotationUtils.getAnnotation(ServiceAlias.class, Controller.class);
        System.out.println(component4);
    }
}

输出:

@org.springframework.stereotype.Component(value=)
@org.springframework.stereotype.Component(value=serviceAlias)
@org.springframework.stereotype.Service(value=serviceAlias)
null

注意版本,本文是spring-boot 2.2.1.RELEASE,对应spring 5.2.1.RELEASE,其他版本可能稍有不同

可以看到,虽然ServiceAlias上只有@Service,但通过AnnotationUtils.getAnnotation方法会解析得到@Component,而通过AnnotatedElementUtils.getMergedAnnotation方法还可以将@Service#value的值赋给@Component#value。

3. @SpringBootApplication

我们都知道@SpringBootApplication注解,等于@EnableAutoConfiguration,@ComponentScan,@SpringBootConfiguration三个注解的组合。
Spring是怎样将三个注解的整合到一个注解的呢?

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    @AliasFor(annotation = EnableAutoConfiguration.class)
    Class<?>[] exclude() default {};

    @AliasFor(annotation = EnableAutoConfiguration.class)
    String[] excludeName() default {};

    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};

    @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};

}

通过@AliasFor,即使用户使用的是@SpringBootApplication,
Spring还是可以通过AnnotationUtils#getAnnotation,AnnotatedElementUtils#getMergedAnnotation等方法,解析到@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan等注解,并取得对应属性。

理解这点对后面看SpringBoot源码帮助很大。


参考:
《SpringBoot深入理解 – @AliasFor注解的作用》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值