说说自定义注解的场景及实现

概述

  • Java注解基本知识
  • 如何访问注解

Java注解基本知识

  • 注解是代码的附属信息,不能干扰代码的正常执行,无论删除或增加注解,代码都能够正常执行
  • 定义注解使用@interface修饰符
  • Java预定义注解被称为元注解,它们被Java编译器使用,比如:@Retention注解和@Target注解,前者定义注解的保留期限,后者定义注解的应用目标
  • 注解的成员声明和接口的方法声明类似,还可以使用default关键字指定成员的默认值
  • 如果注解只有一个成员,则成员名必须取名为value(),使用时如果给成员赋值可以不写成员名和赋值符号’=’
  • 如果注解有多个成员,在赋值时如果只给value()成员赋值,也可以不写成员名和赋值符号’=’
  • 如果在赋值时要同时给多个成员赋值,则必须写成员名和赋值符号’=’
  • 所有注解类都隐式继承与java.lang.annotation.Annotation,但是注解不允许显示继承于其他的接口

有个问题,Java中所有类都隐式继承与Object类这个说法正确吗?

如何访问注解

通过Java的反射机制读取注解的信息
若要通过反射来读取注解信息,那么被定义的注解的保留期限必须是RententionPolicy.RUNTIME,
只有该策略下的注解信息会被保留在目标类代码的字节码中,并且当类加载器加载字节码时会将注解信息加载到JVM中

定义注解

1
2
3
4
5
@Retention(RetentionPolicy.RUNTIME) // 定义@NeedTest注解的保留期限,该注解会保存到目标类的字节码中,并且会被类加载器加载到JVM中
@Target(ElementType.METHOD) // 定义@NeedTest注解的应用目标,这是一个方法级别的注解
public @interface NeedTest {
boolean value() default true; // 单个成员,成员名必须是value(), 默认值是true
}

使用注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MyService {

public void saySomething(){
System.out.println("say something");
}

@NeedTest(true) // 成员名value()设置为true
public void sayHello(String name){
System.out.println("hello "+ name);
}

@NeedTest(false) // 成员名value()设置为false
public void sayHi(String name){
System.out.println("hi " + name);
}
}

访问注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test
public void testCustomAnnotation() {
Class clazz = MyService.class;
Method[] methods = clazz.getDeclaredMethods();
if (methods.length == 0){
System.out.println("method " + clazz.getName() + " has no declared method");
}else {
for (Method method : methods){
NeedTest annotation = method.getAnnotation(NeedTest.class); // 所有自定义的注解都隐式继承自java.lang.annotation.Annotation接口,但是不允许显示继承其他接口
if (annotation == null){
System.out.println("method" + method.getName() + " has not annotated @NeedTest");
}else {
boolean value = annotation.value();
System.out.println(method.getName() + " has annotated @NeedTest and value = " + value);
}
}
}
}

参考链接

《精通Spring4.x——企业应用开发实践》 第8章 基于@AspectJ和Schema的AOP 8.2 Java5.0注解知识快速进阶