设计模式 - 责任链模式

概念

将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。

常见例子

Servlet Filter、Spring Interceptor均使用此设计模式,
最常见的是javax.servlet.Filter,Servlet Filter 是 Java Servlet 规范中定义的组件,翻译成中文就是过滤器,它可以实现对 HTTP 请求的过滤功能,比如鉴权、限流、记录日志、验证参数等。
假如要实现一个Filter,功能是针对所有的rest接口进行签名验证,签名正确的执行接口逻辑,错误的返回错误信息。我们只需要实现Filter接口即可。

@Component
public class RestSecurityFilter implements Filter {
	private static final Logger logger = LoggerFactory.getLogger(RestSecurityFilter.class);

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub

	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {

		if (request instanceof HttpServletRequest) {
			// 校验安全性
			HttpServletRequest httpReq = (HttpServletRequest) request;
			RequestMatcher matcher = new AntPathRequestMatcher("/rest/**");
			if(matcher.matches(httpReq)) {
				String sign = httpReq.getHeader("sign");
				// 具体签名算法略...
				boolean passed = validate(httpReq);
				// 校验不通过,返回错误信息,不再执行下一职责
				if (!passed) {
					HttpServletResponse rp = (HttpServletResponse) response;
					rp.setStatus(HttpStatus.SC_BAD_REQUEST);
					rp.addHeader("restful validate error",
							" 400 , Method Not Allowed,please check restful called paramters ! ");
					rp.getWriter()
							.write("Method Not Allowed,please check restful called paramters !");
					return;
				}
			}
		}
		// 放行,执行下一Filter
		chain.doFilter(request, response);
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub

	}

}

web.xml中配置

  	<filter>
	    <filter-name>restSecurityFilter</filter-name>
	    <filter-class>com.xxx.filter.restSecurityFilter</filter-class>
	</filter>
	<filter-mapping>
	    <filter-name>restSecurityFilter</filter-name>
	    <url-pattern>/rest/*</url-pattern>
	</filter-mapping>

需求场景

业务上需要校验企业信息,依次按照企业名称、社会统一信用代码、注册号等信息进行匹配,其中每种匹配规则有自己的业务逻辑,匹配成功的,不进行下一规则匹配。全部匹配完成之后,如未匹配成功则记为匹配失败。

使用责任链的好处是各业务处理指责单一,易扩展。如后期要加入新的匹配规则,则只需要新增一个handler业务处理类即可,其它均不需要修改。

代码示例

public class CalibrateHandlerChain {
    private CalibrateHandler head = null;
    private CalibrateHandler tail = null;

    public void addHandler(CalibrateHandler handler) {
        handler.setNextHandler(null);
        if (head == null) {
            head = handler;
            tail = handler;
            return;
        }
        tail.setNextHandler(handler);
        tail = handler;
    }

    public void process(List<Company> companyList) {
        if (head != null) {
            head.process(companyList);
        }
    }

}
@Component
public abstract class CalibrateHandler {

    /**
     * next handler,此处使用链表方式实现,也可使用数组
     */
    protected CalibrateHandler nextHandler = null;

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

    /**
     * loop execution the method of calibrateHandlerChain
     */
    public final void process(List<Company> companyList) {
		// 执行当前的handle,执行完成后,进入下一handler
        doHandle(companyList);
        if (nextHandler != null) {
            nextHandler.process(companyList);
        }
    }

    /**
     * abstract method subclass to impl
     *
     * @param companyList
     */
    protected abstract void doHandle(List<Company> companyList);

}

@Component
@Order(1)
public class XXXHandler extends CalibrateHandler {

    @Override
    protected void doHandle(List<Company> companyList) {
        // 企业名称匹配

    }
}

@Component
@Order(2)
public class YYYHandler extends CalibrateHandler {

    @Override
    protected void doHandle(List<Company> companyList) {
        // 社会统一信用代码匹配

    }
}

...

调用方

@Service
public class xxxService {
    @Autowired
    private List<CalibrateHandler> calibrateHandlerList;
	
	public void calibrateCompany(List<Company> companyList) {
		CalibrateHandlerChain chain = new CalibrateHandlerChain();
		// calibrateHandlerList中元素按照@Order排序,依次加入责任链
		calibrateHandlerList.forEach(handler -> chain.addHandler(handler));
		chain.process(companyList);
	}

}

设计模式 - 责任链模式

上一篇:谁说Wacom数位板不能当3D扫描仪用呢


下一篇:No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalanc