JAVA注解知多少

118 阅读2分钟

一、快速上手

定义一个注解最重要的就是使用@Target和@Retention注解对自定义的注解进行标注。

@Target(ElementType.TYPE)
@Rentention(RetentionPolicy.RUNTIME)
public @interface Duty{
    String type() default "";
    int order() default 0;
}

下面介绍一下@Target和@Rentention这两个元注解

  • @Target:用于标注自定义注解的使用范围,取值如下

    • TYPE:作用在类、接口、枚举上
    • FIELD:作用在成员变量上
    • METHOD:作用在方法上
    • PARAMETER:作用在方法参数上
  • @Rentention:用于指示注解的生效范围,取值如下,其中的RUNTIME在实际开发中常用,只有它可以支持在程序运行时通过反射获取注解。

    • SOURCE
    • CLASS
    • RUNTIME(重点关注):程序运行时可以通过反射获取

二、实际应用

考虑如下场景,在责任链模式中,我们通常需要一个责任链对象,来构建和维护各个handler的执行顺序,能否自定义一个注解,这个注解会将具体的Handler类加入一个List中,并且定义其在List中的执行顺序呢?当然可以!

场景来源juejin.cn/post/716084…

回看前面的自定义注解@Duty,其中两个属性:

  • type:用于指定Handler用于处理何种场景
  • order:用于标识先后顺序,值越小,执行顺序越靠前
public class HandleChainManager {
    /**
     * 存放责任链路上的具体处理类
     * k-具体业务场景名称
     * v-具体业务场景下的责任链路集合
     */
    private Map<String, List<IHandler>> handleMap;

    /**
     * 存放系统中责任链具体处理类
     * @param handlerList
     */
    public void setHandleMap(List<IHandler> handlerList) {
        handleMap = handlerList
                .stream()
                .sorted(Comparator.comparingInt(h -> AnnotationUtils.findAnnotation(h.getClass(), Duty.class).order()))
                .collect(Collectors.groupingBy(handler -> AnnotationUtils.findAnnotation(handler.getClass(), Duty.class).type()));
    }

    /**
     * 执行具体业务场景中的责任链集合
     * @param type 对应@Duty注解中的type,可以定义为具体业务场景
     * @param t 被执行的参数
     */
    public <T, R> R executeHandle(String type, T t) {
        List<IHandler> handlers = handleMap.get(type);
        R r = null;
        if (CollectionUtil.isNotEmpty(handlers)) {
            for (IHandler<T, R> handler : handlers) {
               r = handler.handle(t);
            }
        }
        return r;
    }
}