Java注解的执行器

问题起源

最近我们在研究注解,由注解引入,我们“被迫”去学习Java中的反射,反射学习的差不多了,我们再回过头来看看如何去处理注解。

今天,我们先说一下注解学习过程中的一点收获:注解,仅仅只是标注,具体让程序怎么理解注解,仍然需要我们自己来实现。

为了让问题和结论更清晰,我们来自己实现一个注解。

自定义注解

我们首先使用@interface定义了一个注解:我们内心给予这个注解的含义是,定义在类中属性域上,其值value表示转换为字符串时的名称,然而注解定义不包括执行解释,但从定义上看不到任何执行逻辑。

1
2
3
4
5
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SpName {
public String value() default "";
}

重点在于注解的使用与执行:如下,我们定义了一个类Animal,其中给一个属性name标注了注解@SpName("animal-name"),然后,我们在其中toString方法中来解释注解,如下所示:

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
package com.qw.anno;

import com.jfinal.kit.LogKit;

import java.lang.reflect.Field;

public class Animal {

@SpName("animal-name")
public String name;
public int age;

@Override
public String toString() {
StringBuilder result = new StringBuilder();
for (Field field: this.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
if (field.isAnnotationPresent(SpName.class)) {
String annotationValue = field.getAnnotation(SpName.class).value();
result.append(annotationValue).append(":").append(field.get(this)).append(";");
} else {
result.append(field.getName()).append(":").append(field.get(this)).append(";");
}
} catch (IllegalAccessException e) {
System.out.println("异常");
}
}
return result.toString();
}
}

代码编写完后,我们先来验证一下程序:

1
2
3
4
Animal animal = new Animal();
animal.age = 15;
animal.name = "牛牛";
System.out.println(animal.toString());

执行结果:

1
animal-name:牛牛;age:15;

成功执行!

关键代码

获得注解执行的关键代码在于,通过反射获取到类中所有的域:

1
for (Field field: this.getClass().getDeclaredFields()) 

以及,遍历域的过程中,判断当前域是否被添加了SpName注解:

1
2
3
if (field.isAnnotationPresent(SpName.class)) {
....
}

而获取注解的值的代码为:

1
String annotationValue = field.getAnnotation(SpName.class).value();

如此,我们便能够按照自定义的方式来解释执行注解,从而达到自定义注解的方式。

我所一直纠结的地方

其实,我心理一直想要的注解形式是如下的形式:

1
2
3
4
@BeforeOrAfterAction("")
public void method() {
....
}

其中,注解BeforeOrAfterAction表示在函数执行前后做某些指定工作,比如做方法执行的权限检查等等。其实在慢慢寻找答案的过程中,我们发现,这个问题并不属于注解的解决范畴,而确切的说法是AOP:面向切面编程来实现这种思路,常见的包括Spring AOP,以及各个程序中见到的拦截器都是这种实现思路。