0x00 注解例子
写一个注解
import java.lang.annotation.Retention;
        import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String getValue() default "no description";
}
使用一个注解
@MyAnnotation(getValue = "annotation on class")
public class User {
    @MyAnnotation(getValue = "annotation on field")
    public String name;
    @MyAnnotation(getValue = "annotation on method")
    public void hello() {}
}
获取一个注解
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
    public static void main(String[] args) throws Exception {
        Class<User> clazz = User.class;
        MyAnnotation annotationOnClass = clazz.getAnnotation(MyAnnotation.class);
        System.out.println(annotationOnClass.getValue());
        Field name = clazz.getField("name");
        MyAnnotation annotationOnField = name.getAnnotation(MyAnnotation.class);
        System.out.println(annotationOnField.getValue());
        Method hello = clazz.getMethod("hello", null);
        MyAnnotation annotationOnMethod = hello.getAnnotation(MyAnnotation.class);
        System.out.println(annotationOnMethod.getValue());
    }
}
说明
一般像我这样的Python程序员,看到这个注解,想到的肯定是Python里的装饰器,但是实际上,这两者基本没有什么关系
如果对一个方法使用了注解,然后调用方法,会发现注解没有任何装饰器的作用,和我们上面获取一个注解的方式一样,Java里的注解主要是用来被非注解的方法调用,一般是通过反射的方式,也就是在调用方法前,获取它的注解并操作注解的内容
Java里的注解就像标签,是程序判断执行的依据,比如@Before就是在测试方法之前执行
@Retention(RetentionPolicy.RUNTIME)是元注解,就是加在注解上的注解,Rentention用来指定注解的保留策略
因为注解主要被反射读取,反射执行读取内存中的字节码信息,保留策略设置为RUNTIME,可以运行时读取,如果不设置,会报错,不信可以去掉@Retention(RententionPolicy.RUNTIME)尝试一下
大多数情况下,我们只需要使用注解,无需定义和执行,框架会将注解类和读取注解的程序隐藏起来,不阅读源码不知道注解怎么使用
0x01 模拟框架的注解
写几个注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyBefore {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAfter {
}
使用注解
public class User {
    @MyBefore
    public void init() {
        System.out.println("init");
    }
    @MyAfter
    public void destroy() {
        System.out.println("destroy");
    }
    @MyTest
    public void testSave() {
        System.out.println("save");
    }
    @MyTest
    public void testDelete() {
        System.out.println("delete");
    }
}
框架如何调用注解
public class Test {
    public static void main(String[] args) throws Exception {
        Class clazz = User.class;
        Object obj = clazz.newInstance();
        Method[] methods = clazz.getMethods();
        List<Method> myBeforeList = new ArrayList<Method>();
        List<Method> myAfterList = new ArrayList<Method>();
        List<Method> myTestList = new ArrayList<Method>();
        for (Method method : methods) {
            if (method.isAnnotationPresent(MyBefore.class)) {
                myBeforeList.add(method);
            } else if (method.isAnnotationPresent(MyTest.class)) {
                myTestList.add(method);
            } else if (method.isAnnotationPresent(MyAfter.class)) {
                myAfterList.add(method);
            }
        }
        for (Method testMethod : myTestList) {
            for (Method beforeMethod : myBeforeList) {
                beforeMethod.invoke(obj);
            }
            testMethod.invoke(obj);
            for (Method afterMethod : myAfterList) {
                afterMethod.invoke(obj);
            }
        }
    }
}
执行结果
init
save
destroy
init
delete
destroy
自己写一遍体会一下就能明白
通过反射获取一个类,获取类中的方法和属性,根据方法和属性的注解和注解的参数进行一些判断处理操作
 
          