1.职责链路模式

1.1UML图

1.2 职责链路模式的概念

为了避免处理对象的耦合关系,将对象连成一个链,沿着这个链进行访问,直到有一个对象处理位置;

1.3 优点

1.按照一定的顺序执行判断;

2.避免校验对象之间耦合关系;

3.不用担心没有代码没有执行到;

2.职责链路模式在过滤器(Filter)中的使用

1.源码查看

 1.ApplicationDispatcher 

这段代码总共做了三件事:1.过滤器链创建;2.过滤链逐个过滤;3.释放过滤链资源

 private void invoke(ServletRequest request, ServletResponse response,
State state) throws IOException, ServletException { //。。。。。。。。前面的代码省略
// Get the FilterChain Here
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet); //创建过滤器校验链条 // Call the service() method for the allocated servlet instance
try {
// for includes/forwards
if ((servlet != null) && (filterChain != null)) {
filterChain.doFilter(request, response); //进行过滤器校验
}
// Servlet Service Method is called by the FilterChain
} catch (ClientAbortException e) {
//。。。。。。。省略中间错误判断代码
} // Release the filter chain (if any) for this request
try {
if (filterChain != null)
filterChain.release();//释放过滤器资源
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
wrapper.getLogger().error(sm.getString("standardWrapper.releaseFilters",
wrapper.getName()), e);
// FIXME: Exception handling needs to be similar to what is in the StandardWrapperValue
}
//。。。。。。。。。后面的代码省略 }

2.ApplicationFilterFactory(过滤链条创建过程)

从下面可以看出主要是一下操作:

  1.初始化ApplicatFilterChain 过滤器校验链;

  2.从上下文环境中,获取之前配置的过滤器数据

  3.将符合URL,serveletName的过滤器配置到ApplicationFilterChain中

 public static ApplicationFilterChain createFilterChain(ServletRequest request,
Wrapper wrapper, Servlet servlet) { // If there is no servlet to execute, return null
if (servlet == null)
return null; // Create and initialize a filter chain object 初始化链式对象
ApplicationFilterChain filterChain = null;
if (request instanceof Request) {
Request req = (Request) request;
if (Globals.IS_SECURITY_ENABLED) {
// Security: Do not recycle
filterChain = new ApplicationFilterChain();
} else {
filterChain = (ApplicationFilterChain) req.getFilterChain();
if (filterChain == null) {
filterChain = new ApplicationFilterChain();
req.setFilterChain(filterChain);
}
}
} else {
// Request dispatcher in use
     filterChain = new ApplicationFilterChain();
} filterChain.setServlet(servlet);
filterChain.setServletSupportsAsync(wrapper.isAsyncSupported()); // Acquire the filter mappings for this Context 获取过滤器配置的上下文
StandardContext context = (StandardContext) wrapper.getParent();
FilterMap filterMaps[] = context.findFilterMaps(); // If there are no filter mappings, we are done
if ((filterMaps == null) || (filterMaps.length == 0))
return filterChain; // Acquire the information we will need to match filter mappings
DispatcherType dispatcher =
(DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR); String requestPath = null;
Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
if (attribute != null){
requestPath = attribute.toString();
} String servletName = wrapper.getName(); // Add the relevant path-mapped filters to this filter chain 将符合需求的过滤器加入到过滤链中
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue;
}
if (!matchFiltersURL(filterMaps[i], requestPath))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
filterChain.addFilter(filterConfig);
} // Add filters that match on servlet name second
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue;
}
if (!matchFiltersServlet(filterMaps[i], servletName))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
filterChain.addFilter(filterConfig);
} // Return the completed filter chain
return filterChain;
}

3.ApplicationFilterChain(过滤链增加的具体过程)

这个方法比较简单:1.数组扩容;2.增加新的过滤器;

private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];//过滤器存储的实体类
private int pos = 0;//当前过滤位置
private int n = 0;//存储的过滤器的总数
public static final int INCREMENT = 10;
void addFilter(ApplicationFilterConfig filterConfig) {
// Prevent the same filter being added multiple times
for(ApplicationFilterConfig filter:filters)
if(filter==filterConfig)
return; if (n == filters.length) {
ApplicationFilterConfig[] newFilters =
new ApplicationFilterConfig[n + INCREMENT];
System.arraycopy(filters, 0, newFilters, 0, n);
filters = newFilters;
}
filters[n++] = filterConfig; }

4.ApplicationFilterChain 的doFilter方法

处理过程:

  1.获取pos位置的过滤器;

  2.Filter执行,将当前过滤链对象,作为参数进行传递

  3.pos过滤器后移1位进行调用,直到pos大于总过滤器位置;

   @Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException { if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
try {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction<Void>() {
@Override
public Void run()
throws ServletException, IOException {
internalDoFilter(req,res);
return null;
}
}
);
} catch( PrivilegedActionException pe) {
Exception e = pe.getException();
if (e instanceof ServletException)
throw (ServletException) e;
else if (e instanceof IOException)
throw (IOException) e;
else if (e instanceof RuntimeException)
throw (RuntimeException) e;
else
throw new ServletException(e.getMessage(), e);
}
} else {
internalDoFilter(request,response);
}
}
//实际处理过滤任务的方法
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException { // Call the next filter if there is one
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];//pos默认是从0开始的,调用后+1
try {
Filter filter = filterConfig.getFilter(); if (request.isAsyncSupported() && "false".equalsIgnoreCase(
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
}
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal(); Object[] args = new Object[]{req, res, this};
SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
} else {
filter.doFilter(request, response, this);//这里是最重要的一点,过滤器将过滤链对象作为一个参数向下传递,从而可以自动的进行链式校验
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.filter"), e);
}
return;
}
//。。。。。。。。。。省略部分代码 }

2.UML图(上面的链式调用的图,如有错误还请指出)

3.手写一个通用校验链

业务需求:前端传来数据,动态SQL拼接,判断SQL各个部分是否数据有问题;

1.定义接口

/**
* 参数校验锁链管理
* @param
* @author lpf
*/
public interface CheckChain{
public abstract void doCheck(Param param) throws Exception;
}

2.对过滤参数进行约束

public interface Param<T extends Param> {
public abstract <T> T get();
}

3.定义过滤接口

@Service
public interface CheckFilter<T extends Param> {
/**
* 参数校验方法
* @param chain
* @return
*/
public abstract void checkParam(Param<T> param, CheckChain chain) throws Exception;
}

4.默认链式校验实现类

/**
* 默认链式检查
*/
public class DefaultCheckChain implements CheckChain {
/**
*
*/
private ParamCheckWapper[] wappers = new ParamCheckWapper[0]; private static final int INCREMENT = 10; private int n = 0; private int pos = 0; //进行链式检查
@Override
public void doCheck(Param filed) throws Exception {
if(pos < n){
ParamCheckWapper wapper = wappers[pos++];
CheckFilter paramCheck = wapper.getParamCheck();
Assert.notNull(paramCheck,"链式类不能为空");
paramCheck.checkParam(filed,this);
}
} /**
* 增加要进行过滤处理的类
* @param checkWapper
*/
public void addCheck(ParamCheckWapper checkWapper){ for(ParamCheckWapper wapper : wappers){
if(wapper == checkWapper){return;} ;
} if(n == wappers.length){
ParamCheckWapper[] newWappers = new ParamCheckWapper[n + INCREMENT];
System.arraycopy(wappers, 0, newWappers, 0, n);
wappers = newWappers;
}
wappers[n++] = checkWapper; } }

5.过滤实现类(可以有多个)

/**
* select参数校验
* @author lpf
* @since 2019-11-08
*/
public class SelectParamCheck implements CheckFilter<CheckParam> { /**
* 参数校验
* @param param
* @param chain
*/
@Override
public void checkParam(Param<CheckParam> param, CheckChain chain) throws Exception{
CheckParam checkParam = param.get();
List<SelectField> selects = checkParam.getSelect();
List<String> columns = checkParam.getColumnList();
//对select参数进行校验
selects.forEach(select -> {
String filed = select.getFiled().toLowerCase();
boolean flag = columns.contains(filed);
if(!flag) throw new RuntimeException(select.getFiled()+"不存在,请刷新页面重新选择查询字段!!!");
}); }

6.过滤类注册(可以通过yml配置反射生成,或者通过手动注册)

@Service
public class SearchConfigService { /**默认检查链*/
private static DefaultCheckChain checkChain ;
/**过滤链路表配置*/
static{
checkChain = new DefaultCheckChain();
//参数检查器
ParamCheckWapper selectParamCheck = new ParamCheckWapper(new SelectParamCheck(),"SelectParamCheck");
ParamCheckWapper groupParamCheck = new ParamCheckWapper(new GroupbyParamCheck(), "groupParamCheck");
ParamCheckWapper conditionParamCheck = new ParamCheckWapper(new ConditionParamCheck(), "conditionParamCheck");
ParamCheckWapper orderbyParamCheck = new ParamCheckWapper(new OrderbyParamCheck(), "orderbyParamCheck"); //参数链表增加过滤类
checkChain.addCheck(selectParamCheck);
checkChain.addCheck(groupParamCheck);
checkChain.addCheck(conditionParamCheck);
checkChain.addCheck(orderbyParamCheck);
} /**
* 参数校验
*/
public void doCheck(Param param) throws Exception {
checkChain.doCheck(param);
}

  以上,就是职责链路模式的简单使用,可以通过泛型进行代码剥离,后续涉及到链式校验的时候就可以通过限制参数进行多样使用。降低代码的耦合度;

至此,职责链路设计模式的介绍就结束了;

基础设计模式-03 从过滤器(Filter)校验链学习职责链模式的更多相关文章

  1. 设计模式之美:Chain of Responsibility(职责链)

    索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):实现后继者链. 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系. 将这些对象连成一条链,并沿着这条 ...

  2. atitit.设计模式(1)--—职责链模式(chain of responsibility)最佳实践O7 日期转换

    atitit.设计模式(1)---职责链模式(chain of responsibility)最佳实践O7 日期转换 1. 需求:::日期转换 1 2. 可以选择的模式: 表格模式,责任链模式 1 3 ...

  3. atitit.(设计模式1)--—职责链(chain of responsibility)最佳实践O7 转换日期

    atitit.设计模式(1)---职责链模式(chain of responsibility)最佳实践O7 日期转换 1. 需求:::日期转换 1 2. 能够选择的模式: 表格模式,责任链模式 1 3 ...

  4. Java设计模式之职责链设计模式

    1.什么是-职责链设计模式 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求 ...

  5. Filter体现职责链模式

    1. 前言 Filter—Filter 技术是servlet2.3 新增加的功能.完成的流程:对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后 ...

  6. 重温设计模式(三)——职责链模式(chain of responsibility)

    一. 写在前面的 这么多的设计模式,我觉得职责链是我第一次看上去最简单,可是回想起来却又最复杂的一个模式. 因此,这个文章我酝酿了很久,一直也没有胆量发出来,例子也是改了又改,可是仍然觉得不够合理.所 ...

  7. 《javascript设计模式与开发实践》阅读笔记(13)—— 职责链模式

    职责链模式 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. 书里的订单的例子 假设我们负责一个售卖手机 ...

  8. CSharp设计模式读书笔记(14):职责链模式(学习难度:★★★☆☆,使用频率:★★☆☆☆)

    职责链模式(Chain of Responsibility  Pattern):避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象 ...

  9. 职责链模式(chain of responsibility)

    一. 写在前面的 这么多的设计模式,我觉得职责链是我第一次看上去最简单,可是回想起来却又最复杂的一个模式. 因此,这个文章我酝酿了很久,一直也没有胆量发出来,例子也是改了又改,可是仍然觉得不够合理.所 ...

随机推荐

  1. window10下通过docker安装swoole,运行laravel-swoole服务

    最近公司压测一个接口,用laravel框架,业务逻辑就是从缓存中取数据,tps总是上不去,于是决定换下swoole来替换php-fpm,来处理php请求,tps比原来高了好几倍. 现在有个问题就是wi ...

  2. STL中的string

    string常用函数 1.构造函数 string(const char *s); //用c字符串s初始化 string(int n,char c); //用n个字符c初始化 string类还支持默认构 ...

  3. 为什么阿里巴巴Java开发手册中不允许魔法值出现在代码中?

    在阅读<阿里巴巴Java开发手册>时,发现有一条关于关于常量定义的规约,具体内容如下: 图中的反例是将数据缓存起来,并使用魔法值加链路 id 组成 key,这就可能会出现其他开发人员在复制 ...

  4. 日期时间设置 QDate, QTime, QDateTime

    #!/usr/bin/python3 from PyQt5.QtCore import QDate, QTime, QDateTime, Qt now = QDate.currentDate() pr ...

  5. 说出 Servlet 的生命周期,并说出 Servlet 和 CGI 的区别。

    Servlet 被服务器实例化后,容器运行其 init 方法,请求到达时运行其 service 方法,service 方法自动派 遣运行与请求对应的 doXXX 方法(doGet,doPost)等,当 ...

  6. 学习nginx从入门到实践(四) 基础知识之nginx基本配置语法

    nginx基本配置语法 1.http相关 展示每次请求的请求头: curl -v http://www.baidu.com 2.nginx日志类型 error.log. access.log log_ ...

  7. Mac搭建Fluter应用环境

    1.创建一个路径.例如我创建是: /Users/chenghui/ 然后创建一个文件夹: development 把下载好的Fluter 解压到当前目录下: development /Users/ch ...

  8. Java 源码刨析 - String

    [String 是如何实现的?它有哪些重要的方法?] String 内部实际存储结构为 char 数组,源码如下: public final class String implements java. ...

  9. 消息队列——RabbitMQ的基本使用及高级特性

    文章目录 一.引言 二.基本使用 1. 简单示例 2. work queue和公平消费消息 3. 交换机 三.高级特性 1. 消息过期 2. 死信队列 3. 延迟队列 4. 优先级队列 5. 流量控制 ...

  10. vc++,MFC,组合框控件设置时0xC0000005: 读取位置 0x00000020 时发生访问冲突

    511.exe 中的 0x78bb5dec (mfc90ud.dll) 处未处理的异常: 0xC0000005: 读取位置 0x00000020 时发生访问冲突 _AFXWIN_INLINE int ...