一、快速上手
定义一个注解最重要的就是使用@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中的执行顺序呢?当然可以!
回看前面的自定义注解@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;
}
}