springboot基于注解方式实现策略模式

springboot基于注解方式实现策略模式

在项目开发的过程中,我们经常会遇到很多的业务分支,一般我们都采用switch或者if else简单粗暴来处理,当每次我们需要新增一个分支业务逻辑时,就需要修改整体业务逻辑。
因此在项目中,可以采用策略模式进行优化
例如:
使用策略模式发送不同的信息

1、定义策略分类

/**
*@Description 定义策略分类
*@Author aogula
*@Date 2021/1/7
*@Time 13:57
*/
public enum MsgType {
    /**
     * 微信消息
     */
    WECHAT_MSG,
    /**
     * 短信消息
     */
    SMS_MSG;
}

2、定义策略注解

/**
*@Description 策略注解
*@Author aogula
*@Date 2021/1/7
*@Time 14:00
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Type {
    MsgType value();
}

3、定义策略接口

/**
*@Description 策略接口
*@Author aogula
*@Date 2021/1/7
*@Time 13:58
*/
public interface MsgHandler {
    /**
     * 发送信息
     * @param msg
     */
    void handleMsg(String msg);
}

4、定义实现类

4.1短信消息实现类
/**
*@Description 短信消息策略实现类
*@Author aogula
*@Date 2021/1/7
*@Time 13:59
*/
@Component
@Type(value = MsgType.SMS_MSG)
public class SmsMsgHandler implements MsgHandler {

    @Override
    public void handleMsg(String msg) {
        System.out.println("发送短信信息:" + msg);
    }
}
4.2微信消息实现类
/**
*@Description 微信消息策略实现类
*@Author aogula
*@Date 2021/1/7
*@Time 14:00
*/
@Component
@Type(value = MsgType.WECHAT_MSG)
public class WechatMsgHandler implements MsgHandler{

    @Override
    public void handleMsg(String msg) {
        System.out.println("发送微信信息: " + msg);
    }
}

5、策略初始化

5.1获取策略
/**
 * Description:
 *
 * @author: aogula
 * @date Created on 2021/1/7 13:40
 */
@Component
public class MsgHandlerContext {

    /**
     * 注入bean上下文
     */
    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 存放所有策略类Bean的map
     */
    public static Map<MsgType, Class<MsgHandler>> msgTypeClassMap= new HashMap<>();

    public MsgHandler getMsgHandler(MsgType type) {
        Class<MsgHandler> baseMsgHandlerClass = msgTypeClassMap.get(type);
        // 可以定义全局异常进行处理
        if(baseMsgHandlerClass==null) throw new IllegalArgumentException("没有类型");
        // 从容器中获取对应的策略Bean
        return applicationContext.getBean(baseMsgHandlerClass);
    }
}
5.2策略注册
/**
*@Description 将策略注册到map容器中
*@Author aogula
*@Date 2021/1/7
*@Time 14:08
*/
@Component
public class MsgConfig implements ApplicationContextAware {

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        //获取所有策略注解的Bean
        applicationContext.getBeansWithAnnotation(Type.class).
                entrySet().iterator().forEachRemaining(entrySet -> {
            Class<MsgHandler> baseMsgHandler = (Class<MsgHandler>) entrySet.getValue().getClass();
            MsgType value = baseMsgHandler.getAnnotation(Type.class).value();
            // 将class加入MsgHandlerContext的map中,注解的value作为key
            MsgHandlerContext.msgTypeClassMap.put(value, baseMsgHandler);
        });
    }
}

6、测试接口

@RestController
@RequestMapping("/task")
public class TaskController {
   
    @Autowired
    private MsgHandlerContext msgHandlerContext;

    @GetMapping("msg")
    public void handleMsg(MsgType msg) {
        MsgHandler handler = msgHandlerContext.getMsgHandler(msg);
        handler.handleMsg("我是具体的一条信息,hello world!");
    }
}

7、结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8、问题

如果下面这句代码出现空指针异,说明实现类走了JDK代理模式,导致无法获取到注解

MsgType value = baseMsgHandler.getAnnotation(Type.class).value();

解决:
方法一:可以将策略接口类修改为抽象类,让实现类走Cglib代理
方法二:合理规划包路径,因为扫描包路径过大,导致所使用的的bean被spring代理
解决方法可以参考其他文章:https://www.jianshu.com/p/b69e64121b97

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值