通过自定义注解和反射实现策略模式
今天在写一个工单系统时,工单审批通过后,需要根据不同的工单类型选择不同的处理方式
非常适合用自定义注解+反射来实现,研究了一番,记录一下成果.
类型枚举类
先定义一个类型的枚举类
@AllArgsConstructor
@Getter
public enum TypeEnum {
TYPE1(1,"类型一"),
TYPE2(2,"类型二");
private Integer value;
private String desc;
//定义这个静态变量,时为了方便通过类型编码获取到描述信息
private final static Map<Integer, TypeEnum> ENUM_MAP =
Maps.uniqueIndex(EnumSet.allOf(TypeEnum.class), TypeEnum::getValue);
public static String getDesc(Integer value) {
TypeEnum oneEnum = ENUM_MAP.get(value);
if (oneEnum!=null){
return oneEnum.getDesc();
}
return null;
}
}
自定义注解类
@Documented
//ElementType.TYPE表示允许被修饰的注解作用在类、接口和枚举上,其他还有,FIELD(允许作用在属性字段上),METHOD(允许作用在方法上),PARAMETER(允许作用在方法参数上),CONSTRUCTOR(允许作用在构造器上),LOCAL_VARIABLE(允许作用在本地局部变量)上,ANNOTATION_TYPE(允许作用在注解上),PACKAGE(允许作用在包上)
//{}里面可以有多种类型,这里指用到了TYPE类型
@Target({ElementType.TYPE})
//表示自定义注解将存在到哪个生命周期,RetentionPolicy.SOURCE(注解只保留在源文件),RetentionPolicy.CLASS(注解被保留到class文件),RetentionPolicy.RUNTIME(jvm加载class文件之后,仍然存在)
@Retention(RetentionPolicy.RUNTIME)
//@Interited 用来声明一个注解
public @interface HandleType {
//TypeEnum就是上面定义的枚举类型
TypeEnum[] value();
}
定义公共接口和实现类
定义需要实现的功能
public interface HandleService {
void handleMethed();
}
两个处理实现类
@Slf4j
@Service
//处理方式一
@HandleType(value = TypeEnum.TYPE1)
public class HandleOne implements HandleService {
@Override
public void handleMethed() {
log.info("处理方式一执行!");
}
}
@Slf4j
@Service
//处理方式二
@HandleType(value = TypeEnum.TYPE2)
public class HandleTwo implements HandleService {
@Override
public void handleMethed() {
log.info("处理方式二执行!");
}
}
启动时加载所有加了@HandleType注解的类的对象
@Slf4j
@Configuration
public class SpringBeanConfig {
@Resource
private ApplicationContext applicationContext;
/**
* 处理方式对象集合
*/
private Map<Integer, HandleService> handleServiceMap = new HashMap<>();
//@PostConstruct是Java自带的注解,在方法上加该注解会在项目启动的时候执行该方法,也可以理解为在spring容器初始化的时候执行该方法。@PostConstruct注解的方法将会在依赖注入完成后被自动调用
@PostConstruct
public void init() {
//ApplicationContext 应用上下文 getBeansWithAnnotation() 根据注解类型获取的对应的 bean名称 和 bean对象
//遍历bean对象
applicationContext.getBeansWithAnnotation(HandleType.class).forEach((k, v) -> {
//AnnotationUtils.findAnnotation(A.Class,B.Class)查找第A类中,是否涵盖B注解。如果有,就返回此注解,没有就返回空
//@HandleType注解的value值可以有多个
TypeEnum[] typeEnums = AnnotationUtils.findAnnotation(v.getClass(),HandleType.class).value();
//遍历value值放到map中
for (int i = 0; i < typeEnums.length; i++) {
Integer type = typeEnums[i].getValue();
handleServiceMap.put(type, (HandleService) v);
}
});
log.info("Succeed to load service: {}", handleServiceMap);
}
public HandleService getHandleService(Integer type) {
return handleServiceMap.get(type);
}
}
根据不同处理类型,动态选择不同处理方式
@Service
@Slf4j
public class OrderService {
@Resource
private SpringBeanConfig springBeanConfig;
//获取处理方式对象
private HandleService getService(Integer handleType) {
HandleService handleService = springBeanConfig.getHandleService(handleType);
if (handleService == null) {
log.info("handleType:{} baseService is null",handleType);
return null;
}
return handleService;
}
//根据处理类型选择不同处理方式
private void deal(String handleType) {
HandleService handleService = getService(handleType);
//处理业务数据
handleService.handleMethed();
log.info("业务数据处理完成");
}
}
总结
HandleOne和HandleTwo是两种处理策略
TypeEnum定义了有哪几种策略
HandleType是自定义注解本体
SpringBeanConfig把所有的策略汇总到一个map中
OrderService具体的业务实现
标签:反射,自定义,class,value,TypeEnum,HandleType,注解,public From: https://www.cnblogs.com/joule/p/17080149.html