设计模式(五)责任链模式——在Spring中使用责任链模式

前言

设计模式(四)责任链模式 —— 责任链模式结构 中分析了责任链模式的结构,在日常开发中经常结合spring容器来使用,借助容器的一些特性,同时可以解决一些责任链模式的不足。

场景案例

如以电商系统下单流程为例,简化一下这个流程,只包含库存、价格、优惠券三个业务步骤。

类图结构

在spring中优雅的使用责任链模式

定义业务用到的基础类

定义OrderDTO和ResultDTO

import java.io.Serializable;

/**
 * @author lishuzhen
 * @createTime 2022年06月19日 22:40:00
 */
public class ResultDTO implements Serializable {
    private String msg;

    public static ResultDTO ok(){
        return new ResultDTO();
    }

    public ResultDTO() {
        msg = "ok";
    }

    public String getMsg() {
        return msg;
    }
}


/**
 * @author lishuzhen
 * @createTime 2022年06月19日 22:15:00
 */
public class OrderDTO {
    private String orderNo;

    public String getOrderNo() {
        return orderNo;
    }

    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
    }
}

定义抽象的处理器接口

  • 定义doFilter方法,由子类实现处理器的内部逻辑,注意在doFilter方法的最后一步要记得调用doNextFilter()
  • 定义doNextFilter方法,由抽象类完成调用下一个处理器的代码。
/**
 * 处理器抽象类
 *
 * @author lishuzhen
 * @createTime 2022年06月19日 22:52:00
 */
public abstract class AbstractOrderChainHandler {

    private AbstractOrderChainHandler nextHandler;

    /**
     * 执行过滤方法
     *
     * @param orderDTO
     * @return
     */
    abstract protected ResultDTO doFilter(OrderDTO orderDTO);

    /**
     * 执行下一个处理器
     *
     * @param orderDTO
     * @param resultDTO
     * @return
     */
    protected ResultDTO doNextHandler(OrderDTO orderDTO, ResultDTO resultDTO) {
        if (nextHandler == null) {
            return resultDTO;
        }
        return nextHandler.doFilter(orderDTO);
    }

    public void setNextHandler(AbstractOrderChainHandler nextHandler) {
        this.nextHandler = nextHandler;
    }
}

定义处理器的子类实现

  • 必须实现抽象的处理器接口,供容器启动时获取所有的处理器实现类
  • 通过@Order注解,标识当前处理器在整个责任链中的位置。建议区间设置的大一些,后续增加处理器时比较方便。
/**
 * 订单提交-库存计算处理器
 *
 * @author lishuzhen
 * @createTime 2022年06月19日 22:57:00
 */
@Service
@Order(100)
public class StockOrderChainHandler extends AbstractOrderChainHandler {
    /**
     * 执行过滤方法
     *
     * @param orderDTO
     * @return
     */
    @Override
    protected ResultDTO doFilter(OrderDTO orderDTO) {
        System.out.println("库存计算处理");
        return doNextHandler(orderDTO, ResultDTO.ok());
    }
}
/**
 * 订单提交-价格计算处理器
 *
 * @author lishuzhen
 * @createTime 2022年06月19日 22:59:00
 */
@Service
@Order(300)
public class PriceOrderChainHandler extends AbstractOrderChainHandler {
    /**
     * 执行过滤方法
     *
     * @param orderDTO
     * @return
     */
    @Override
    protected ResultDTO doFilter(OrderDTO orderDTO) {
        System.out.println("价格计算处理");
        return doNextHandler(orderDTO, ResultDTO.ok());
    }
}
/**
 * 订单提交-优惠券计算处理器
 *
 * @author lishuzhen
 * @createTime 2022年06月19日 22:59:00
 */
@Service
@Order(200)
public class CouponOrderChainHandler extends AbstractOrderChainHandler {
    /**
     * 执行过滤方法
     *
     * @param orderDTO
     * @return
     */
    @Override
    protected ResultDTO doFilter(OrderDTO orderDTO) {
        System.out.println("优惠券处理");
        return doNextHandler(orderDTO, ResultDTO.ok());
    }
}

封装组合责任链

  • 通过@Autowired修饰责任链(处理器的集合),spring容器会按照@order的顺序组装一个有序的list集合。
  • 通过@PostConstruct修饰constructChain()方法,使容器回调此方法,完成为每一个处理设置它的下一个处理器
  • 定义firstHandler,表示这是当前责任链路顶端的第一个处理器。
/**
 * 订单处理责任链
 *
 * @author lishuzhen
 * @createTime 2022年06月19日 23:05:00
 */
@Service
public class OrderChainHandler {

    @Autowired
    private List<AbstractOrderChainHandler> chain;

    private AbstractOrderChainHandler firstHandler;


    @PostConstruct
    private void constructChain() {
        if (chain == null || chain.size() == 0) {
            throw new RuntimeException("not found order chain handler");
        }
        firstHandler = chain.get(0);
        for (int i = 0; i < chain.size(); i++) {
            if (i == chain.size() - 1) {
                chain.get(i).setNextHandler(null);
            } else {
                chain.get(i).setNextHandler(chain.get(i + 1));
            }
        }
    }

    public ResultDTO executionChain(OrderDTO orderDTO) {
        return firstHandler.doFilter(orderDTO);
    }
}

写一个测试接口

@Controller
@RequestMapping("/lsz")
public class OrderTestController {

    @Autowired
    private OrderChainHandler orderChainHandler;


    @ResponseBody
    @RequestMapping("testOrder")
    public Object testOrder(String orderNo){
        return orderChainHandler.executionChain(new OrderDTO()).getMsg();
    }
}

查看日志

可以看到控制台日志按照责任链处理器的顺序打印了日志

总结

优点

  • 降低了各个处理器之间的耦合,各处理器只关注处理自身的内部逻辑,然后抛给下一个处理器即可。
  • 不需要关注具体的上下游调用关系,在组装责任链时通过spring的特性动态注入下一个处理器的调用关系。
  • 通过@Order注解,可灵活调整各处理器之间的调用顺序

缺点

  • 会增加程序的复杂度,需评估酌情使用,不可为了设计模式而用设计模式。
### Spring 中实现责任链设计模式Spring框架中,责任链模式可以通过多种方式实现。一种常见的方式是在Spring Web应用程序中利用`Filter Chain`机制[^1]。 #### 使用过滤器链 (Filter Chain)Spring Web环境中,开发者能够定义一系列的过滤器来处理HTTP请求。这些过滤器按照配置顺序依次被调用,在每个过滤器内部可以选择继续传递请求至下一个过滤器或是中断整个链条。这种结构非常适合用于实施安全措施如CSRF防护、解决跨域资源共享(CORS)等问题以及字符集编码调整等操作。 ```java public class CustomFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { // 执行自定义逻辑前的操作 // 继续沿链向下传递控制权给下一层过滤器或目标资源 chain.doFilter(request, response); // 可选:在此处放置响应后的处理代码 } catch (Exception e) { throw new ServletException("Custom filter failed", e); } } @Override public void init(FilterConfig config) {} @Override public void destroy() {} } ``` 为了使上述过滤器生效并参与责任链流程,需将其注册到Spring容器内: ```xml <filter> <filter-name>customFilter</filter-name> <filter-class>com.example.CustomFilter</filter-class> </filter> <filter-mapping> <filter-name>customFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ``` 或者采用基于Java Config的方法进行声明: ```java @Configuration public class WebConfig { @Bean public FilterRegistrationBean customFilter(){ final FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new CustomFilter()); registration.addUrlPatterns("/api/*"); return registration; } } ``` #### 利用AOP与拦截器构建更灵活的责任链 除了传统的Servlet Filters之外,还可以借助于面向切面编程(AOP),特别是Spring AOP所提供的Advisor和Interceptor组件来创建更加动态化的责任链体系[^3]。 例如,下面展示了如何通过编写环绕通知(`@Around`)来形成一条由不同业务规则构成的任务流水线: ```java @Component @Aspect public class HandlerChainAspect { private List<AbstractCheckHandler> handlerList; @Autowired public HandlerChainAspect(List<AbstractCheckHandler> handlers){ this.handlerList = handlers; } @Around("@annotation(com.wangfei.annotation.Check)") public Object process(ProceedingJoinPoint joinPoint)throws Throwable{ Context context = buildContextFrom(joinPoint.getArgs()); for(AbstractCheckHandler handler : handlerList){ boolean handled = handler.handle(context); if(handled){ break; // 如果当前处理器已经成功处理,则停止后续处理器运行 } } return joinPoint.proceed(); // 若无任何处理器介入则正常转发原方法调用 } private Context buildContextFrom(Object[] args){ // 构造上下文对象... return null; } } ``` 在这个例子中,所有实现了`AbstractCheckHandler`接口的服务都将自动成为责任链的一部分,并且可以根据具体需求自由组合排列它们之间的先后次序[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值