Java Annotation

101 阅读2分钟

@Target

@Target 主要作用是该类型适用的上下文,比如用在类上、方法上或者字段上,但是一个Target只能有一个ElementType,不能多次出现。并在源代码中由java.lang.annotation.ElementType的枚举常量表示。

enum ElementType

ElementType中的常量在java.lang.annotation.Target元注释中使用,用于指定在哪里可以合法地编写给定类型的注释。

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,
    /** Field declaration (includes enum constants) */
    FIELD,
    /** Method declaration */
    METHOD,
   /** Annotation type declaration */
   ANNOTATION_TYPE,
   ... ...
   ... ...
}

For example, the following @Target meta-annotation is illegal:

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD})
public @interface Bogus {
         ...
}

@Target 注解源代码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

@Retention

带有@Retention注释类型的注释要保留多长时间。如果注释类型声明中没有保留注释,则保留策略默认为RetentionPolicy.CLASS。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}
enum RetentionPolicy

RetentionPolicy是一个enum类型的保留策略,它们与Retention元注释类型一起使用,以指定注释要保留多长时间。

public enum RetentionPolicy {
    /**
     * 注解将被编译器丢弃。
     */
    SOURCE,
    /**
     * 注解将由编译器记录在类文件中,但不需要在运行时由VM保留。这是默认行为。
     */
    CLASS,
    /**
     * 注解将由编译器记录在类文件中,并在运行时由VM保留,因此它们可能被反射地读取。
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

自定义一个注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvoidRepeatableCommit {
    long timeout() default 6000;
}

然后我们可以通过Aspect对注解进行切面拦截使用。

@Aspect
@Component
@AllArgsConstructor
public class AvoidRepeatableCommitAspect {

    /**
     * @param point 切点
     */
    @Around("@annotation(avoidRepeatableCommit)")
    public Object around(ProceedingJoinPoint point, AvoidRepeatableCommit avoidRepeatableCommit) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String ip = IPUtils.getIpAddr(request);
        //获取注解
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        //目标类、方法
        String className = method.getDeclaringClass().getName();
        String name = method.getName();
        // .....   
        //执行方法
        return point.proceed();
    }
}

Note

如果在方法上面定义不同的通知,会发生什么?如果发生,执行顺序是什么?比如:

@Around("@annotation(avoidRepeatableCommit)")
@After("@annotation(avoidRepeatableCommit)") 
@Before("@annotation(avoidRepeatableCommit)") 
public Object around(ProceedingJoinPoint point, 
                     AvoidRepeatableCommit avoidRepeatableCommit)
     // will do something...
 }  

@Around 环绕通知总是会先执行,然后是@Before前置通知,最后只@After后置通知,无论目标方法是否发生异常都会执行。

看到这里,你能自己解释下什么是Annotation吗?