通过自定义注解(@Retention @Target)和反射实现策略模式

通过自定义注解(@Retention @Target)和反射实现策略模式

​ 今天在写一个工单系统时,工单审批通过后,需要根据不同的工单类型选择不同的处理方式

非常适合用自定义注解+反射来实现,研究了一番,记录一下成果.


类型枚举类

先定义一个类型的枚举类

@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具体的业务实现

log.info(“业务数据处理完成”);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值