来看一下这个注解的源码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
我们通过@Target元注解的属性值可以看出,这个@Inherited 是专门修饰注解的。
作用:让子类可以继承父类中被@Inherited修饰的注解,注意是继承父类中的,如果接口中的注解也使用@Inherited修饰了,那么接口的实现类是无法继承这个注解的
package com.javacode2018.lesson001.demo18;
import java.lang.annotation.*;
public class InheritAnnotationTest {
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface A1{ //@1
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface A2{ //@2
}
@A1 //@3
interface I1{}
@A2 //@4
static class C1{}
static class C2 extends C1 implements I1{} //@5
public static void main(String[] args) {
for (Annotation annotation : C2.class.getAnnotations()) { //@6
System.out.println(annotation);
}
}
}
@1:定义了一个注解A1,上面使用了@Inherited,表示这个具有继承功能
@2:定义了一个注解A2,上面使用了@Inherited,表示这个具有继承功能
@3:定义接口I1,上面使用了@A1注解
@4:定义了一个C1类,使用了A2注解
@5:C2继承了C1并且实现了I1接口
@6:获取C2上以及从父类继承过来的所有注解,然后输出
运行输出:
@com.javacode2018.lesson001.demo18.InheritAnnotationTest$A2()
从输出中可以看出类可以继承父类上被@Inherited修饰的注解,而不能继承接口上被@Inherited修饰的注解,这个一定要注意
来看一段代码:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Ann12{}
@Ann12
@Ann12
public class UseAnnotation12 {
}
上面代码会报错,原因是:UseAnnotation12上面重复使用了@Ann12注解,默认情况下@Ann12注解是不允许重复使用的。
像上面这样,如果我们想重复使用注解的时候,需要用到@Repeatable注解
先定义容器注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD})
@interface Ann12s {
Ann12[] value(); //@1
}
容器注解中必须有个value类型的参数,参数类型为子注解类型的数组。
要让一个注解可以重复使用,需要在注解上加上@Repeatable注解,@Repeatable中value的值为容器注解,如下代码中的@2
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD})
@Repeatable(Ann12s.class)//@2
@interface Ann12 {
String name();
}
重复使用相同的注解有2种方式,如下面代码
@Ann12(name = "路人甲Java")
@Ann12(name = "Spring系列")
public class UseAnnotation12 {
@Ann12s(
{@Ann12(name = "Java高并发系列,见公众号"),
@Ann12(name = "mysql高手系列,见公众号")}
)
private String v1;
}
com.javacode2018.lesson001.demo18.UseAnnotation12
@Test
public void test1() throws NoSuchFieldException {
Annotation[] annotations = UseAnnotation12.class.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
System.out.println("-------------");
Field v1 = UseAnnotation12.class.getDeclaredField("v1");
Annotation[] declaredAnnotations = v1.getDeclaredAnnotations();
for (Annotation declaredAnnotation : declaredAnnotations) {
System.out.println(declaredAnnotation);
}
}
运行输出:
@com.javacode2018.lesson001.demo18.Ann12s(value=[@com.javacode2018.lesson001.demo18.Ann12(name=Java), @com.javacode2018.lesson001.demo18.Ann12(name=Spring系列)])
-------------
@com.javacode2018.lesson001.demo18.Ann12s(value=[@com.javacode2018.lesson001.demo18.Ann12(name=Java高并发系列), @com.javacode2018.lesson001.demo18.Ann12(name=mysql高手系列)])
上面就是java中注解的功能,下面我们来介绍spring对于注解方面的支持。
代码如下:
package com.javacode2018.lesson001.demo18;
import org.junit.Test;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface A1 {
String value() default "a";//@0
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@A1
@interface B1 { //@1
String value() default "b";//@2
}
@B1("Java") //@3
public class UseAnnotation13 {
@Test
public void test1() {
//AnnotatedElementUtils是spring提供的一个查找注解的工具类
System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation13.class, B1.class));
System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation13.class, A1.class));
}
}
@0:A1注解value参数值默认为a
@1:B1注解上使用到了@A1注解
@2:B1注解value参数值默认为b
@2:UseAnnotation13上面使用了@B1注解,value参数的值为:路人甲java
test1方法中使用到了spring中的一个类AnnotatedElementUtils,通过这个工具类可以很方便的获取注解的各种信息,方法中的2行代码用于获取UseAnnotation13类上B1注解和A1注解的信息。
运行test1方法输出:
@com.javacode2018.lesson001.demo18.B1(value=Java)
@com.javacode2018.lesson001.demo18.A1(value=a)
上面用法很简单,没什么问题。
此时有个问题:此时如果想在UseAnnotation13上给B1上的A1注解设置值是没有办法的,注解定义无法继承导致的,如果注解定义上面能够继承,那用起来会爽很多,spring通过@Aliasfor方法解决了这个问题。
直接上案例,然后解释代码。
package com.javacode2018.lesson001.demo18;
import org.junit.Test;
import org.springframework.core.annotation.AliasFor;
import org.springframework.core.annotation.AnnotatedElementUtils;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface A14 {
String value() default "a";//@0
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@A14 //@6
@interface B14 { //@1
String value() default "b";//@2
@AliasFor(annotation = A14.class, value = "value") //@5
String a14Value();
}
@B14(value = "Java",a14Value = "通过B14给A14的value参数赋值") //@3
public class UseAnnotation14 {
@Test
public void test1() {
//AnnotatedElementUtils是spring提供的一个查找注解的工具类
System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation14.class, B14.class));
System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation14.class, A14.class));
}
}
运行输出:
@com.javacode2018.lesson001.demo18.B14(a14Value=通过B14给A14的value参数赋值, value=Java)
@com.javacode2018.lesson001.demo18.A14(value=通过B14给A14的value参数赋值)
注意上面diam的@3只使用了B14注解,大家认真看一下,上面输出汇总可以看出A14的value值和B14的a14Value参数值一样,说明通过B14给A14设置值成功了。
重点在于代码@5,这个地方使用到了@AliasFor注解:
@AliasFor(annotation = A14.class, value = "value")
这个相当于给某个注解指定别名,即将B1注解中a14Value参数作为A14中value参数的别名,当给B1的a14Value设置值的时候,就相当于给A14的value设置值,有个前提是@AliasFor注解的annotation参数指定的注解需要加载当前注解上面,如:@6
package com.javacode2018.lesson001.demo18;
import org.junit.Test;
import org.springframework.core.annotation.AliasFor;
import org.springframework.core.annotation.AnnotatedElementUtils;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface A15 {
@AliasFor("v2")//@1
String v1() default "";
@AliasFor("v1")//@2
String v2() default "";
}
@A15(v1 = "我是v1") //@3
public class UseAnnotation15 {
@A15(v2 = "我是v2") //@4
private String name;
@Test
public void test1() throws NoSuchFieldException {
//AnnotatedElementUtils是spring提供的一个查找注解的工具类
System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation15.class, A15.class));
System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation15.class.getDeclaredField("name"), A15.class));
}
}
注意上面代码,A15注解中(@1和@2)的2个参数都设置了@AliasFor,@AliasFor如果不指定annotation参数的值,那么annotation默认值就是当前注解,所以上面2个属性互为别名,当给v1设置值的时候也相当于给v2设置值,当给v2设置值的时候也相当于给v1设置值。
运行输出
@com.javacode2018.lesson001.demo18.A15(v1=我是v1, v2=我是v1)
@com.javacode2018.lesson001.demo18.A15(v1=我是v2, v2=我是v2)
从输出中可以看出v1和v2的值始终是相等的,上面如果同时给v1和v2设置值的时候运行代码会报错。
我们回头来看看@AliasFor的源码:
@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注解中value和attribute互为别名,随便设置一个,同时会给另外一个设置相同的值。
当@AliasFor中不指定value或者attribute的时候,自动将@AliasFor修饰的参数作为value和attribute的值,如下@AliasFor注解的value参数值为name
package com.javacode2018.lesson001.demo18;
import org.junit.Test;
import org.springframework.core.annotation.AliasFor;
import org.springframework.core.annotation.AnnotatedElementUtils;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface A16 {
String name() default "a";//@0
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@A16
@interface B16 { //@1
@AliasFor(annotation = A16.class) //@5
String name() default "b";//@2
}
@B16(name="我是v1") //@3
public class UseAnnotation16 {
@Test
public void test1() throws NoSuchFieldException {
//AnnotatedElementUtils是spring提供的一个查找注解的工具类
System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation16.class, A16.class));
System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation16.class, B16.class));
}
}
运行输出:
@com.javacode2018.lesson001.demo18.A16(name=我是v1)
@com.javacode2018.lesson001.demo18.B16(name=我是v1)