【spring微服务】spring-boot之注解回顾
一、元注解
元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。
@Retention、@Documented、@Target、@Inherited、@Repeatable 5 种
1、 @Retention
Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间
- RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
- RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
- RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
2、@Documented
顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。
3、@Target
Target 是目标的意思,@Target 指定了注解运用的地方。
你可以这样理解,当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。
- ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
- ElementType.CONSTRUCTOR 可以给构造方法进行注解
- ElementType.FIELD 可以给属性进行注解
- ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
- ElementType.METHOD 可以给方法进行注解
- ElementType.PACKAGE 可以给一个包进行注解
- ElementType.PARAMETER 可以给一个方法内的参数进行注解
- ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
4、@Inherited
Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有和父类一样的注解,那么这个子类就继承了超类的注解。
两个注解例子
import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * */ @Inherited @Retention(RetentionPolicy.RUNTIME) public @interface Getter { String sex() default ""; } import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * */ @Inherited @Retention(RetentionPolicy.RUNTIME) public @interface Setter { String name() default ""; int length() default 0; }
子类和父类
@Setter(name = "java",length = 30) public class Parent { } @Getter(sex = "男") public class Son extends Parent{ }
测试例子
public class Test { /** *注解属性[名字]=java * 注解属性[长度]=30 * 注解属性[长度]=30 * 注解属性[名字]=java * 注解属性[性别]=男 * @param args */ public static void main(String[] args) { Class<Son> cls=Son.class; //获取类上的所有注解 Annotation[] annotations=cls.getAnnotations(); //获取类上的指定注解 Setter setter= cls.getAnnotation(Setter.class); System.out.println("注解属性[名字]="+setter.name()); System.out.println("注解属性[长度]="+setter.length()); //遍历所有注解 for(Annotation annotation:annotations){ Class c=annotation.annotationType(); if(c.isAssignableFrom(Setter.class)){ Setter set= (Setter) annotation; System.out.println("注解属性[长度]="+set.length()); System.out.println("注解属性[名字]="+set.name()); } if(c.isAssignableFrom(Getter.class)){ Getter get= (Getter) annotation; System.out.println("注解属性[性别]="+get.sex()); } } } }
如果子类和父类使用相同的注解,则子类会覆盖父类的注解
子类和父类
@Setter(name = "java",length = 30) public class Parent { } @Setter(name = "c",length = 12) public class Son extends Parent{ }
测试例子
public class Test { /** * 注解属性[名字]=c * 注解属性[长度]=12 * 注解属性[长度]=12 * 注解属性[名字]=c * @param args */ public static void main(String[] args) { Class<Son> cls=Son.class; //获取类上的所有注解 Annotation[] annotations=cls.getAnnotations(); //获取类上的指定注解 Setter setter= cls.getAnnotation(Setter.class); System.out.println("注解属性[名字]="+setter.name()); System.out.println("注解属性[长度]="+setter.length()); //遍历所有注解 for(Annotation annotation:annotations){ Class c=annotation.annotationType(); if(c.isAssignableFrom(Setter.class)){ Setter set= (Setter) annotation; System.out.println("注解属性[长度]="+set.length()); System.out.println("注解属性[名字]="+set.name()); } if(c.isAssignableFrom(Getter.class)){ Getter get= (Getter) annotation; System.out.println("注解属性[性别]="+get.sex()); } } } }
5、@Repeatable
Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。
什么样的注解会多次应用呢?通常是注解的值可以同时取多个。
举个例子,一个人他既是程序员又是产品经理,同时他还是个画家。
@interface Persons { Person[] value(); } @Repeatable(Persons.class) @interface Person{ String role default ""; } @Person(role="artist") @Person(role="coder") @Person(role="PM") public class SuperMan{ }
注意上面的代码,@Repeatable 注解了 Person。而 @Repeatable 后面括号中的类相当于一个容器注解。
什么是容器注解呢?就是用来存放其它注解的地方。它本身也是一个注解。
我们再看看代码中的相关容器注解。
@interface Persons { Person[] value(); }
按照规定,它里面必须要有一个 value 的属性,属性类型是一个被 @Repeatable 注解过的注解数组,注意它是数组。
如果不好理解的话,可以这样理解。Persons 是一张总的标签,上面贴满了 Person 这种同类型但内容不一样的标签。把 Persons 给一个 SuperMan 贴上,相当于同时给他贴了程序员、产品经理、画家的标签。
我们可能对于 @Person(role=”PM”) 括号里面的内容感兴趣,它其实就是给 Person 这个注解的 role 属性赋值为 PM ,大家不明白正常,马上就讲到注解的属性这一块。
二、注解的属性
注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
@Inherited @Retention(RetentionPolicy.RUNTIME) public @interface Setter { String name() default ""; int length() default 0; }
三、注解提取
1、注解与反射
注解通过反射获取。首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
然后通过 getAnnotation() 方法来获取 Annotation 对象。
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
或者是 getAnnotations() 方法。
public Annotation[] getAnnotations() {}
四、组合注解
1、一个组合注解的例子
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Inherited @Documented public @interface Config { String pathVaule() default "组合注解"; } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Inherited @Documented @Config public @interface Company { String path() default ""; } @Company(path = "sd") public class NameClass { }
2、解析组合注解
sd 组合注解 注解详情:interface java.lang.annotation.Retention 注解详情:interface java.lang.annotation.Target 注解详情:interface java.lang.annotation.Inherited 注解详情:interface java.lang.annotation.Documented 注解详情:interface com.spring.test.service.javacore.annotation.Config public static void test02() { //spring提供的AnnotationUtils工具类 Config config= AnnotationUtils.findAnnotation(NameClass.class,Config.class); Company company=AnnotationUtils.findAnnotation(NameClass.class,Company.class); System.out.println(company.path()); System.out.println(config.pathVaule()); Annotation[] annotations=NameClass.class.getDeclaredAnnotations(); for(Annotation annotation:annotations){ Annotation[] annotations1= annotation.annotationType().getAnnotations(); for(Annotation a:annotations1){ System.out.println("注解详情:"+a.annotationType()); } } }
浙公网安备 33010602011771号