首先,来思考一个场景(以下单为例)。如果一个下单的请求,调用的服务比较多,也就是一个请求的调用链比较长,这时候该怎么去设计我们的程序?实现的方法多种多样,比较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 : 订单手机号不能为空