Java注解

引言

  • 最近项目中需要在服务器端的REST层加入鉴权的机制,即客户端在HTTP请求中带上用户token,调用REST层的每一个API前需要经过鉴权的步骤,即向中心服务器发送用户token查询该用户是否具有调用此API的权限,如果有则可以调用,没有则不能调用;
  • 由于REST层的API都已经写好,且鉴权的代码和API的代码分离,故初步决定反射机制实现这一功能;
  • 由于用到了反射,顺便学习了下java注解;
  • 本文参考这里

注解的作用

  • 注释是给人看的,注解是给程序看的;
  • Annotation可被用于packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数);
  • 注解的最主要作用是为特定的数据打上一个标记,以便以后拿来使用;
  • 执行注解的原则:有什么标记(注解)就干什么事;
  • 注释本质上是一个标记,可以在编译、类加载、运行时被读取,并执行相应的操作;
  • 具体来说,注解有以下作用:生成文档、跟踪代码依赖性、在编译时进行格式检查;

元注解

  • 元注解用于注解其他的注解;
  • @Target
    • ElemenetType.CONSTRUCTOR 构造器声明
    • ElemenetType.FIELD 域声明(包括 enum 实例)
    • ElemenetType.LOCAL_VARIABLE 局部变量声明
    • ElemenetType.METHOD 方法声明
    • ElemenetType.PACKAGE 包声明
    • ElemenetType.PARAMETER 参数声明
    • ElemenetType.TYPE 类,接口(包括注解类型)或enum声明
  • @Retention
    • RetentionPolicy.SOURCE 注解将被编译器丢弃
    • RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃
    • RetentionPolicy.RUNTIME VM 将在运行期也保留注释,因此可以通过反射机制读取注解的信息
  • @Documented
    • @Documented 将此注解包含在javadoc中 ,它代表着此注解会被javadoc工具提取成文档;
  • @Inherited
    • @Inherited 允许子类继承父类中的注解;

基本注解

  • @Override:告诉编译器检查本方法确保被重写,只能作用于方法,不能作用于其他元素;
  • @Deprecated:修饰类或者方法,告诉编译器这个被修饰的类或方法已经过时,编译时提出警告信息;
  • @Suppress Warnings:取消编译器警告信息,作用于修饰的元素及所有子元素;
  • @Safe Varargs:专门抑制堆污染警告;
  • 其他的java定义好的注解直接查阅API文档即可;

自定义注解

  • 自定义注解修饰各种语法成分
1
2
3
4
5
6
//注解的定义
package test13;

public @interface TestA {

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package test13;

import java.util.HashMap;
import java.util.Map;

@TestA
public class UserAnnotation {
@TestA //使用了类成员注解
private Integer age;

@TestA //使用了构造方法注解
public UserAnnotation(){

}

@TestA //使用了类方法注解
public void a(){
@TestA //使用了局部变量注解
Map m = new HashMap(0);
}

public void b(@TestA Integer a){ //使用了方法参数注解

}
}
  • 使用元注解
1
2
3
4
5
6
7
8
9
10
11
12
package test13;

import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

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


}
  • 在注解中添加内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//定义注解
package test13;

import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD,ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface TestA {
String name();
int id() default 0;
Class<?> gid();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//使用注解
package test13;

import java.util.HashMap;
import java.util.Map;

@TestA(name = "type", gid = Long.class)
// 类成员注解
public class UserAnnotation {
@TestA(name = "param", id = 1, gid = Long.class)
// 类成员注解
private Integer age;

@TestA(name = "construct", id = 2, gid = Long.class)
// 构造方法注解
public UserAnnotation() {
}

@TestA(name = "public method", id = 3, gid = Long.class)
// 类方法注解
public void a() {
Map m = new HashMap(0);
}

@TestA(name = "protected method", id = 4, gid = Long.class)
// 类方法注解
protected void b() {
Map m = new HashMap(0);
}

@TestA(name = "private method", id = 5, gid = Long.class)
// 类方法注解
private void c() {
Map m = new HashMap(0);
}

public void b(Integer a) {
}
}
  • 配合反射使用注解
    • 一般的做法是,定义annotation生命周期为运行时仍存在,运行时通过反射获取相应的annotation内容,然后根据annotation的内容决定采取下一步的动作;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//定义注解
package test13;

import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD,ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface TestA {
String name();
int id() default 0;
Class<?> gid();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//被注解修饰的类
package test13;

import java.util.HashMap;
import java.util.Map;

@TestA(name = "type", gid = Long.class)
// 类成员注解
public class UserAnnotation {
@TestA(name = "param", id = 1, gid = Long.class)
// 类成员注解
private Integer age;

@TestA(name = "construct", id = 2, gid = Long.class)
// 构造方法注解
public UserAnnotation() {
}

@TestA(name = "public method", id = 3, gid = Long.class)
// 类方法注解
public void a() {
Map m = new HashMap(0);
}

@TestA(name = "protected method", id = 4, gid = Long.class)
// 类方法注解
protected void b() {
Map m = new HashMap(0);
}

@TestA(name = "private method", id = 5, gid = Long.class)
// 类方法注解
private void c() {
Map m = new HashMap(0);
}

public void b(Integer a) {
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//用反射机制使用注解
package test13;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class ParseAnnotation {

public static void parseTypeAnnotation() throws ClassNotFoundException {
//通过反射获取UserAnnotation
Class<?> clazz = Class.forName("test13.UserAnnotation");

//获取类的注解信息,由于注解信息保留到了运行时,所以这里可以获取
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
TestA testA = (TestA) annotation;

//id= 0;name= type;gid= class java.lang.Long (类注解仅有一个)
System.out.println("id= " + testA.id() + ";name= " + testA.name()
+ ";gid= " + testA.gid());
}
}

public static void parseMethodAnnotation() {
//通过反射获取类方法
Method[] methods = UserAnnotation.class.getDeclaredMethods();

for (Method method : methods) {
boolean hasAnnotation = method.isAnnotationPresent(TestA.class);
if (hasAnnotation) {
TestA annotation = method.getAnnotation(TestA.class);

/*
* method = c ; id = 5 ; description = private method; gid= class java.lang.Long
* method = a ; id = 3 ; description = public method; gid= class java.lang.Long
* method = b ; id = 4 ; description = protected method; gid= class java.lang.Long
*/
System.out.println("method = " + method.getName() + " ; id = "
+ annotation.id() + " ; description = "
+ annotation.name() + "; gid= " + annotation.gid());
}
}
}

public static void parseConstructAnnotation() {
//通过反射获取构造器
Constructor[] constructors = UserAnnotation.class.getConstructors();
for (Constructor constructor : constructors) {

boolean hasAnnotation = constructor
.isAnnotationPresent(TestA.class);

if (hasAnnotation) {
TestA annotation = (TestA) constructor
.getAnnotation(TestA.class);

/*
* constructor = test13.UserAnnotation ; id = 2 ; description = construct; gid= class java.lang.Long
*/
System.out.println("constructor = " + constructor.getName()
+ " ; id = " + annotation.id() + " ; description = "
+ annotation.name() + "; gid= " + annotation.gid());
}
}
}

public static void main(String[] args) throws ClassNotFoundException {
parseTypeAnnotation();
parseMethodAnnotation();
parseConstructAnnotation();
}
}
您的支持是对我最大的鼓励!