springboot整合activeMq 二(消费者handler不同逻辑实现)

上篇文章写了简单的生产者消费者实现,这篇生产者不做改变,对消费者如何消费做了升级,不再是上篇单一的实现,而是根据不同的入参执行相应的消费逻辑。
1.先定义一个消息基类,里面参数看你需要,可以为失败重试做准备

@Data
public class BaseAsyncDto {
    /**
     * 重试次数
     */
    private Integer retryTimes=0;

    /**
     * 下次重试时间
     */
    private Date nextRetryTimes;

}

2.定义实现消息入参体(两个类不同的属性做区分)

@Data
public class SmsSend1Dto extends BaseAsyncDto implements Serializable {

    private static final long serialVersionUID = -4882464111301842049L;
  
    private Integer id;
    /**手机号码*/
    private String phoneNo;

}
@Data
public class SmsSend2Dto extends BaseAsyncDto implements Serializable {

    private static final long serialVersionUID = 8436613771808998029L;

    /**手机号码*/
    private String phone;
    private String name;


}

3.定义回调结果,里面包含入参消息基类,为后续失败重试做准备

@Data
public class InvokeResult implements Serializable {

    private boolean success;

    private boolean doRetry;

    private BaseAsyncDto dto;

}

4.定义处理类基类和对应上述两个不同消息体不同处理handler

public interface BaseHandler {

    /**
     * 功能描述: 该handler是否能处理请求
     */
    boolean canHandle(Object obj);

    /**
     * 功能描述: 处理过程
     */
    Callable<InvokeResult> doHandle(Object obj);
}

两个实现类

@Component("smsSend1Handler")
public class SmsSend1Handler implements BaseHandler {

    private static final Logger logger = LogManager.getLogger(SmsSend1Handler.class);
    @Override
    public boolean canHandle(Object obj) {
        return obj instanceof SmsSend1Dto;
    }

    @Override
    public Callable<InvokeResult> doHandle(Object obj) {
        Callable<InvokeResult> res=new Callable<InvokeResult>() {
            @Override
            public InvokeResult call() throws Exception {
                System.out.println("走handler1的逻辑");
                SmsSend1Dto record = (SmsSend1Dto) obj;
                // 返回值
                InvokeResult result = new InvokeResult();
                result.setDoRetry(false);
                result.setDto(record);
                result.setSuccess(true);
                try {
                    //进行处理逻辑
                    System.out.println("走handler1的逻辑"+ JSONUtil.toJsonStr(record));
                }catch (Exception e){
                    logger.error(e.getMessage());
                    onFailure(record, e.getMessage());
                    result.setSuccess(false);
                    return result;
                }

                return result;
            }
        };
       return res;
    }


    /**
     * 功能描述: 失败处理
     */
    private void onFailure(SmsSend1Dto record, String errorInfo) {
       //失败处理
    }
}

第二个doHandle里用了lamda表达式,写法更为简单干净,效果一样

@Component("smsSend2Handler")
public class SmsSend2Handler implements BaseHandler {

    private static final Logger logger = LogManager.getLogger(SmsSend2Handler.class);

    @Override
    public boolean canHandle(Object obj) {
        return obj instanceof SmsSend2Dto;
    }

    @Override
    public Callable<InvokeResult> doHandle(Object obj) {
        return () -> {
            SmsSend2Dto record = (SmsSend2Dto) obj;
            // 返回值
            InvokeResult result = new InvokeResult();
            result.setDoRetry(false);
            result.setDto(record);
            result.setSuccess(true);
            try {
                //进行处理逻辑
                System.out.println("走handler2的逻辑"+ JSONUtil.toJsonStr(record));
            }catch (Exception e){
                logger.error(e.getMessage());
                onFailure(record, e.getMessage());
                result.setSuccess(false);
                return result;
            }

            return result;
        };
    }


    /**
     * 功能描述: 失败处理
     */
    private void onFailure(SmsSend2Dto record, String errorInfo) {
       //失败处理
    }
}

5.改造我们的ConsumerService

@Component
public class ConsumerService  {


    private static final Logger logger = LogManager.getLogger(TestService.class);

    @Autowired
    private List<BaseHandler> handlerList;


    private ExecutorService threadpool = new ThreadPoolExecutor(0, 8,
            60L, TimeUnit.SECONDS, new LinkedBlockingDeque<>());

    /**
     *  消费mq
     *
     */
    @JmsListener(destination = "ActiveMQQueue")
    public void mainListen(String message) throws Exception {
        System.out.println("主流程消费:"+message);

        // 创建任务
        List<Callable<InvokeResult>> callableList= createCallable(message);

        // 任务执行及异常处理
        if (callableList.size()>0){
            runAndExceptionDeal(callableList);
        }
    }


    public List<Callable<InvokeResult>> createCallable(String message){
        List<Callable<InvokeResult>> callableList = new ArrayList<>();
        // 创建任务
        Object obj;
        try {
            //因为@type会报错,所以加一行
            ParserConfig.getGlobalInstance().addAccept("com.*.*.dto.");
            obj = JSON.parse(message);
            // 从数据库读出来的json字符串需要转两次,第一次会转成不带转义符的string,第二次转成的对象
            //可忽略,这是把消息存数据库,需要多处理一遍
            if(obj instanceof String) {
                obj = JSON.parse((String)obj);
            }
        } catch (Exception e) {
            logger.error("JSON解析失败:" + message);
            e.printStackTrace();
            return callableList;
        }
        for (BaseHandler handler : handlerList) {
            if (handler.canHandle(obj)) {
                BaseAsyncDtodto = (BaseAsyncDto)obj;
                callableList.add(handler.doHandle(dto));
                //记录异步执行记录
            }
        }
        return callableList;
    }

    public void runAndExceptionDeal(List<Callable<InvokeResult>> callableList){
        // 任务执行及异常处理
        try {
            List<Future<InvokeResult>> futureList = threadpool.invokeAll(callableList);
            for (Future<InvokeResult> future : futureList) {
                InvokeResult invokeResult = future.get();
                if(invokeResult == null) {
                    logger.error("异步任务执行失败,无法重试");
                }
                if(!invokeResult.isSuccess()) {
                    System.out.println("异步任务执行失败,走失败重试");
                }
            }
        } catch (Exception e) {
            logger.error("unknown exception has been catch!");
        }
    }



}

最后生产者生产的时候要把发送对象转成string哦

@RestController
@RequestMapping("/test")
public class ProviderController {
 
    //注入存放消息的队列,用于下列方法一
    @Autowired
    private Queue queue;
 
    //注入springboot封装的工具类
    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;
 
    @RequestMapping("/send")
    public void send(String name) {
         SmsSend1Dto dto=new SmsSend1Dto();
        dto.setId(1);
        dto.setPhoneNo("1768333");
        jmsMessagingTemplate.convertAndSend(queue, JSONObject.toJSONString(dto, SerializerFeature.WriteClassName));
    }
}

好了,简单的handler实现就完成了,里面还有一些重试啊,记录啊什么的没写进去,不过根据大家的需要自己实现就行了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值