首先,来思考一个场景(以下单为例)。如果一个下单的请求,调用的服务比较多,也就是一个请求的调用链比较长,这时候该怎么去设计我们的程序?实现的方法多种多样,比较low的方法就是把所有服务调用都写到一起,这是不推荐的,巧用设计模式瞬间提高你代码逼格。
一个电商的下单流程一般包括,订单参数校验、调用第三方服务下单、保存订单到本地数据库、保存订单操作日志等等操作。下面用代码来模拟一下这个流程。
一,创建三个处理器,分别为前置处理器、中间处理器、后置处理器,并实现有序接口保证一个处理器有多一个服务调用时,可以顺序调用服务。
/** * 前置处理器 * * @Author: guandezhi * @Date: 2019/5/25 8:06 PM */ public interface Preprocessor<T> extends Sort { /** * 校验操作 * * @param t */ void validate(T t); } /** * 中间处理器 * * @Author: guandezhi * @Date: 2019/5/25 8:06 PM */ public interface MiddlerProcessor<T> extends Sort { /** * 调用服务 * * @param t */ void invoke(T t); } /** * 后置处理器 * * @Author: guandezhi * @Date: 2019/5/25 8:10 PM */ public interface AfterProcessor<T> extends Sort { /** * 保存操作 * * @param t */ void save(T t); }其中有序接口为:
/** * 有序接口 * * @Author: guandezhi * @Date: 2019/5/25 8:11 PM */ public interface Sort { default int getSorted() { return 0; } }二,创建一个处理器增强器,将处理器放到集合中备用
/** * @Author: guandezhi * @Date: 2019/5/26 12:00 AM */ @Data public class ProcessorBuilder { private List<Preprocessor> preprocessorList = new ArrayList<>(); private List<MiddlerProcessor> middlerProcessorList = new ArrayList<>(); private List<AfterProcessor> afterProcessorList = new ArrayList<>(); private ProcessorData processorData; public ProcessorBuilder(Object object) { this.processorData = ProcessorData.builder().Data(object).resultVo(new ResultVo()).build(); } public ServerChain build() { return new ServerChain(preprocessorList, middlerProcessorList, afterProcessorList, processorData); } /** * 通过服务类型将处理器装入集合中 * * @param clazz */ public void addProcessors(Class clazz) { Object serviceBean = ApplicationContextUtil.getBean(clazz); if (serviceBean instanceof Preprocessor) { preprocessorList.add((Preprocessor) serviceBean); } else if (serviceBean instanceof MiddlerProcessor) { middlerProcessorList.add((MiddlerProcessor) serviceBean); } else { afterProcessorList.add((AfterProcessor) serviceBean); } } }这里的ProcessorData为调用链之间传递的参数:
/** * @Author: guandezhi * @Date: 2019/5/26 12:01 AM */ @Data @Builder public class ProcessorData<T> { /** * 入参 */ private T Data; /** * 返回结果 */ private ResultVo<T> resultVo; public ResultVo<T> getResultVo() { return resultVo; } public void setResultVo(ResultVo<T> resultVo) { this.resultVo = resultVo; } }三,创建服务器调用链,服务的调用就在这里完成
/** * 服务器链 * * @Author: guandezhi * @Date: 2019/5/25 11:58 PM */ @Data @AllArgsConstructor public class ServerChain { private List<Preprocessor> preprocessorList; private List<MiddlerProcessor> middlerProcessorList; private List<AfterProcessor> afterProcessorList; private ProcessorData processorData; /** * 按顺序调用服务器链,每个处理器可能有多个服务顺序调用 */ public void process() { preprocessorList.stream().sorted((Preprocessor p1, Preprocessor p2) -> p1.getSorted() - p2.getSorted()) .forEach(p -> p.validate(processorData)); middlerProcessorList.stream().sorted((MiddlerProcessor p1, MiddlerProcessor p2) -> p1.getSorted() - p2.getSorted()) .forEach(p -> p.invoke(processorData)); afterProcessorList.stream().sorted((AfterProcessor p1, AfterProcessor p2) -> p1.getSorted() - p2.getSorted()) .forEach(p -> p.save(processorData)); } }其中ApplicationContextUtil用于获取服务对象,如下:
/** * @Author: guandezhi * @Date: 2019/5/26 12:09 AM */ @Component public class ApplicationContextUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; /** * 通过name获取 Bean. * * @param name * @return */ public static Object getBean(String name) { return getApplicationContext().getBean(name); } /** * 通过class获取Bean. * * @param clazz * @param <T> * @return */ public static <T> T getBean(Class<T> clazz) { return getApplicationContext().getBean(clazz); } /** * 通过name及Clazz返回指定的Bean * * @param name * @param clazz * @param <T> * @return */ public static <T> T getBean(String name, Class<T> clazz) { return getApplicationContext().getBean(name, clazz); } @Autowired public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } /** * 获取applicationContext * * @return */ public static ApplicationContext getApplicationContext() { return applicationContext; } }四,创建四个handler用来具体业务的操作,分别ValidateOrderHandler、CreateOrderHandler、SaveOrderHandler、SaveOrderLogHandler
/** * 校验订单 * * @Author: guandezhi * @Date: 2019/5/25 8:13 PM */ @Slf4j @Service public class ValidateOrderHandler implements Preprocessor<ProcessorData<CreateOrderParam>> { public void validate(ProcessorData<CreateOrderParam> processorData) { CreateOrderParam createOrderParam = processorData.getData(); if (createOrderParam == null) { processorData.getResultVo().setCode(MsgCodeEnum.FAIL.getCode()); return; } if (StringUtils.isEmpty(createOrderParam.getMobile())) { processorData.getResultVo().setCode(MsgCodeEnum.FAIL.getCode()); processorData.getResultVo().setMsg("订单手机号不能为空"); return; } if (StringUtils.isEmpty(createOrderParam.getBuyerName())) { processorData.getResultVo().setCode(MsgCodeEnum.FAIL.getCode()); processorData.getResultVo().setMsg("购买人不能为空"); return; } //TODO 订单其他入参校验 log.info("订单校验完成"); } } /** * 调用第三方服务,创建订单 * * @Author: guandezhi * @Date: 2019/5/25 8:16 PM */ @Slf4j @Service public class CreateOrderHandler implements MiddlerProcessor<ProcessorData<CreateOrderParam>> { public void invoke(ProcessorData<CreateOrderParam> processorData) { if (!MsgCodeEnum.SUCCESS.getCode().equals(processorData.getResultVo().getCode())) { log.info(processorData.getResultVo().getMsg()); return; } //TODO 调用第三方服务下单 log.info("调用第三方服务下单完成"); } } /** * 保存订单到数据库 * * @Author: guandezhi * @Date: 2019/5/25 8:18 PM */ @Slf4j @Service public class SaveOrderHandler implements AfterProcessor<ProcessorData<CreateOrderParam>> { public void save(ProcessorData<CreateOrderParam> processorData) { if (!MsgCodeEnum.SUCCESS.getCode().equals(processorData.getResultVo().getCode())) { return; } //TODO 此处添加保存订单操作 log.info("保存订单到数据库完成"); } @Override public int getSorted() { return 10; } } /** * 保存操作订单日志 * * @Author: guandezhi * @Date: 2019/5/25 8:21 PM */ @Slf4j @Service public class SaveOrderLogHandler implements AfterProcessor<ProcessorData<CreateOrderParam>> { public void save(ProcessorData<CreateOrderParam> processorData) { if (!MsgCodeEnum.SUCCESS.getCode().equals(processorData.getResultVo().getCode())) { return; } //TODO 此处记录订单操作日志 log.info("保存订单操作日志完成"); } @Override public int getSorted() { return 20; } }五,创建订单服务,通过服务调用链来处理请求。
/** * @Author: guandezhi * @Date: 2019/5/26 1:24 AM */ @Slf4j @Service public class OrderService { @Autowired private ValidateOrderHandler validateOrderService; @Autowired private CreateOrderHandler createOrderService; @Autowired private SaveOrderHandler saveOrderService; @Autowired private SaveOrderLogHandler saveOrderLogService; public ResultVo createOrder(CreateOrderParam createOrderParam) { ResultVo resultVo = new ResultVo(); ProcessorBuilder processorBuilder = new ProcessorBuilder(createOrderParam); processorBuilder.addProcessors(ValidateOrderHandler.class); processorBuilder.addProcessors(CreateOrderHandler.class); processorBuilder.addProcessors(SaveOrderHandler.class); processorBuilder.addProcessors(SaveOrderLogHandler.class); ServerChain serverChain = processorBuilder.build(); serverChain.process(); return resultVo; } }六,做个简单的测试
1.正常情况下的日志,服务按顺序调用。
2019-05-26 21:29:43.542 INFO 798 --- [nio-8080-exec-2] c.g.p.s.o.handler.ValidateOrderHandler : 订单校验完成 2019-05-26 21:29:43.542 INFO 798 --- [nio-8080-exec-2] c.g.p.s.o.handler.CreateOrderHandler : 调用第三方服务下单完成 2019-05-26 21:29:43.543 INFO 798 --- [nio-8080-exec-2] c.g.p.s.order.handler.SaveOrderHandler : 保存订单到数据库完成 2019-05-26 21:29:43.543 INFO 798 --- [nio-8080-exec-2] c.g.p.s.o.handler.SaveOrderLogHandler : 保存订单操作日志完成2.参数校验不通过或者其他异常时的日志,此时服务没有往下走,直接返回了。
2019-05-29 01:40:21.581 INFO 4099 --- [nio-8080-exec-7] c.g.p.s.o.handler.CreateOrderHandler : 订单手机号不能为空