基于双向责任链的接口设计

Posted kuailefangyuan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于双向责任链的接口设计相关的知识,希望对你有一定的参考价值。

基于双向责任链的接口设计

基于双向责任链的接口特点如下:

1、一个完整的接口由基于LinkedList的filterChain责任链组实现,filterChain包括多个公共业务filter和最终业务处理handler,而handler本身也是filter。

2、每个filter包括process()往后处理和onPostProcess()回调,责任链先调用process()正向单向执行。责任链执行到最后一个节点-Handler业务处理完毕后,再依次调用OnPostProcess()回调方法,回溯反向执行责任链,从而实现单向链表的逆向回调,即所谓的双向责任链。

3、filter节点之间通过ProcessContext上下文对象来存储责任链过程中的相关参数,如request、response对象等。

双向责任链的执行流程如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Esm3sGfV-1647005253517)(C:\\Users\\meifangyuan\\AppData\\Roaming\\Typora\\typora-user-images\\image-20220306120257481.png)]


1、正向调用接口IProcessFilter

/**
 * 责任链调用接口
 */
public interface IProcessFilter 

    /**
     * 链节点的处理
     * 1、当前节点需要持有链表FilterChain以继续调用后续链的执行
     * 2、同时需要持有上个节点传递过来的回调对象,以执行完后回调到上个节点的后处理流程。
     * @param processContext
     * @param filterChain
     * @param callback
     * @throws InterruptedException
     * @throws ProcessException
     */
    public void process(ProcessContext processContext, IFilterChain filterChain, IFilterCallback callback) throws InterruptedException, ProcessException;


2、回调接口IFilterCallback

/**
 * 责任链回调接口
 */
public interface IFilterCallback 
    /**
     * 回调,因为是下个节点直接调用,除上下文外无需多余参数
     * @param context
     * @throws ProcessException
     */
    public void onPostProcess(ProcessContext context) throws ProcessException;

3、ProcessContext业务执行上下文

/**
 * 业务执行上下文
 */
@Getter
@Setter
public class ProcessContext 

    /**
     * 请求原文
     */
    private String jsonRequest;

    /**
     * 请求
     */
    private BaseRequest<? extends BaseResponse> request;

    /**
     * 响应
     */
    private BaseResponse response;

    /**
     * 应答原文
     */
    private String jsonResponse;

    /**
     * 处理业务
     */
    private BusinessService businessService;

    /**
     * 服务开始时间
     */
    private long startServiceTime = System.currentTimeMillis();

    /**
     * 服务结束时间
     */
    private long endServiceTime;

    public ProcessContext(String jsonRequest) 
        this.jsonRequest = jsonRequest;
    

4、双向责任链IFilterChain接口及实现

/**
 * 责任链
 * 只需持有处理上下文、回调对象即可
 */
public interface IFilterChain 
    void process(ProcessContext processContext, IFilterCallback callback) throws ProcessException, InterruptedException;

/**
 * 基于LinkedList的双向责任链
 */
public class LinkedFilerChain implements IFilterChain 

    private LinkedList<IProcessFilter> filters;

    public LinkedFilerChain(LinkedList<IProcessFilter> filters) 
        this.filters = filters;
    

    /**
     * 执行责任链
     * @param processContext
     * @param callback
     * @throws ProcessException
     */
    @Override
    public void process(ProcessContext processContext, IFilterCallback callback) throws ProcessException, InterruptedException 
        assert this.filters != null && !this.filters.isEmpty();

        // 从第一个filter开始执行
        IProcessFilter processFilter = this.filters.removeFirst();
        processFilter.process(processContext, this, callback);
    

5、业务处理抽象基类AbstractServiceHandler定义

/**
 * 抽象serviceHandler基类
 */
public abstract class AbstractServiceHandler implements IProcessFilter 
    @Override
    public void process(ProcessContext processContext, IFilterChain filterChain, IFilterCallback callback) throws ProcessException 
        /**
         * 注意这里handle处理因为是责任链最后一个节点,只需执行回调即可,无需持有filterChain
         */
        handle(processContext, callback);
    

    abstract public void handle(ProcessContext processContext, IFilterCallback callback) throws ProcessException;

以添加用户接口AddUserServiceHandler为例:

public class AddUserServiceHandler extends AbstractServiceHandler 

    @Override
    public void handle(ProcessContext processContext, IFilterCallback callback) throws ProcessException 
        log.info("添加用户开始");
        try 
            Thread.sleep(100L);
         catch (InterruptedException e) 
            e.printStackTrace();
        
        log.info("添加用户结束");

        // 设置响应内容
        AddUserRequest req = (AddUserRequest) processContext.getRequest();
        AddUserResponse resp = (AddUserResponse)processContext.getResponse();
        resp.setErrCode("SUCCESS");
        resp.setErrMsg("添加用户成功");
        resp.setUserName(req.getUserName());
        resp.setAge(req.getAge());

        // 此处为一个完整服务正向责任链的执行终点,此处执行回调,逆向执行责任链
        callback.onPostProcess(processContext);
    

6、完整定义接口业务BusinessService

一个完整的接口业务BusinessService包括如下:

1、请求request报文,返回响应response报文

2、公共业务处理filters

3、具体业务处理ServiceHandler

4、业务执行,执行双向责任链filterChain (filters+serviceHandler)

public class BusinessService 

    private IRequest request;

    private IResponse response;

    @Setter
    @Getter
    private BaseRequest<? extends BaseResponse> requestPrototype;

    /**
     * 前处理filters
     */
    private List<IProcessFilter> filterTemplate;

    /**
     * 最终处理serviceHandler
     */
    private AbstractServiceHandler businessHandler;

    /**
     * 执行一个完整的业务
     */
    public void execute(ProcessContext processContext, IFilterCallback callback) throws ProcessException, InterruptedException 
        log.info("开始处理业务请求: ", System.nanoTime());

        processContext.setBusinessService(this);

        // 构建责任链
        LinkedList<IProcessFilter> filters = new LinkedList<>();
        filters.addAll(this.filterTemplate);
        filters.add(businessHandler);
        LinkedFilerChain filterChain = new LinkedFilerChain(filters);

        // 执行双向责任链
        try 
            filterChain.process(processContext, callback);
         finally 
            log.info("完成业务处理", System.nanoTime());
        

    

6、接口示例

以下以添加用户接口AddUserService为示例:

1、添加用户请求报文AddUserRequest

2、执行责任链

具体执行顺序如下:

  1. JsonConvertFilter
  2. checkRequestTimeFilter
  3. AddUserServiceHandler

3、返回添加用户响应报文AddUserResponse

Spring容器配置xml文件配置addUserService接口如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="jsonConvertFilter" class="com.fymei.filter.JsonConvertFilter" />
    <bean id="checkRequestTimeFilter" class="com.fymei.filter.CheckRequestTimeFilter" />

    <util:list id="addUserFilters">
        <ref bean="jsonConvertFilter" />
        <ref bean="checkRequestTimeFilter" />
    </util:list>

    <bean id="addUserService" class="com.fymei.framework.BusinessService">
        <property name="requestPrototype">
            <bean class="com.fymei.jsonbean.AddUserRequest" />
        </property>
        <property name="filterTemplate" ref="addUserFilters"/>
        <property name="businessHandler">
            <bean class="com.fymei.service.AddUserServiceHandler"/>
        </property>
    </bean>
</beans>

AddUserService接口的执行测试如下:

@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/application-context.xml")
public class TestAddUser 

    @Qualifier("addUserService")
    @Autowired
    private BusinessService addUserService;

    @org.junit.Test
    public void test() throws InterruptedException, ProcessException 
        // 构建请求报文
        AddUserRequest req  = new AddUserRequest();
        req.setUserName("zhangsan");
        req.setAge(20);
        req.setRequestTimestamp(new Date());
        String json = JSON.toJSONString(req);
        log.info("请求报文:", json);

        // 执行addUserService服务
        addUserService.execute(new ProcessContext(json), new IFilterCallback() 
            @Override
            public void onPostProcess(ProcessContext context) throws ProcessException 
                context.setEndServiceTime(System.currentTimeMillis());
                long diffTime = context.getEndServiceTime() - context.getStartServiceTime();
                log.info("双向责任链执行完毕, 服务耗时" + diffTime);
                log.info("响应报文:", context.getJsonResponse());
            
        );

    

以上是关于基于双向责任链的接口设计的主要内容,如果未能解决你的问题,请参考以下文章

模拟javaWeb责任链的设计

JDK设计模式之——责任链

责任链的常见用法?

设计模式——责任链(chain of responsibiltiy)

一个搞定责任链的注解

基于区块链的投票系统的设计与实现