设计模式-责任链模式
理解
责任链的执行序列是一环连着一环,后一环的执行依赖前一环的执行,层层递进.
流程图
组成部分
- 链条:负责承前启后;
- 链条上的环:执行业务逻辑,决定是否继续执行下一个环(有的情况由链条决定);
- 执行流:
- 前期:由外层到里层;
- 后期:由里层到外层
特点
- 链条上相邻的环之间会影响,影响入参和出参;
- 每个环负责相对独立的任务,比如有的负责字符编码设置,有的负责流的编码和解码(比如gzip),有的负责记录日志等
实例
一个简单的 demo
项目代码
链条类
public class DaoFilterChain { private List<IFilter> filterList = new ArrayList<>(); private int index = 0; private boolean hasAddDefaultFilter = false; public DaoFilterChain addFilter(IFilter filter) { if (hasAddDefaultFilter) { throw new RuntimeException("自定义过滤器必须在默认过滤器之前添加"); } this.filterList.add(filter); return this; } /*** * 专门添加最基础的DaoFilter * @param filter * @return */ public DaoFilterChain addDefaultFilter(IFilter filter) { this.filterList.add(filter); hasAddDefaultFilter = true; return this; } public void reset() { this.index = 0; } private IFilter next() { if (index == filterList.size()) { return null; } IFilter filter = filterList.get(index); index++; return filter; } public void doFilter(DaoRequest request, DaoResponse response) { IFilter filter = next(); if (null == filter) { System.out.println("结束 index :" + index); return; } filter.doFilter(request, response, this); } }
过滤器接口
public interface IFilter { /*** * 最后一个过滤器一定是DefaultDaoFilter * @param request * @param response * @param filterChain */ void doFilter(DaoRequest request, DaoResponse response, DaoFilterChain filterChain); }
javax.servlet.Filter
过滤器核心方法 :
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;
链条:org.apache.catalina.core.ApplicationFilterChain
源码见:http://www.docjar.com/html/api/org/apache/catalina/core/ApplicationFilterChain.java.html
doFilter 核心代码 (去掉了其他代码):
ApplicationFilterConfig filterConfig = filters[pos++]; Filter filter = null; filter = filterConfig.getFilter(); filter.doFilter(request, response, this);
过滤器实例 :支持跨域
其他过滤器实例
租户拦截器
接口:
public interface IRequestFilter { void doFilter(HttpFormContentRequestWrapper request, HttpServletResponse response, RequestFilterChain filterChain) throws IOException, ServletException; }
链条类 RequestFilterChain
public class RequestFilterChain { private List<IRequestFilter> filterList = new ArrayList<>(); private final static Logger logger = LoggerFactory.getLogger(RequestFilterChain.class); private ThreadLocal<Integer> indexLocal = new ThreadLocal<Integer>() { @Override protected Integer initialValue() { return 0; } }; private ThreadLocal<Boolean> hasAddDefaultFilter = new ThreadLocal<Boolean>() { @Override protected Boolean initialValue() { return Boolean.FALSE; } }; public RequestFilterChain addFilter(IRequestFilter filter) { if (hasAddDefaultFilter.get()) { throw new RuntimeException("自定义过滤器必须在默认过滤器之前添加"); } this.filterList.add(filter); return this; } public RequestFilterChain removeFilter(IRequestFilter filter) { this.filterList.remove(filter); return this; } public RequestFilterChain addDefaultFilter(IRequestFilter filter) { this.filterList.add(filter); hasAddDefaultFilter.set(true); // DefaultFormRequestWrapperFilter defaultDaoFilter = (DefaultFormRequestWrapperFilter) filter; return this; } public void reset() { indexLocal.set(0); } private IRequestFilter next() { if (indexLocal.get() == filterList.size()) { return null; } IRequestFilter filter = filterList.get(indexLocal.get()); // index++; indexLocal.set(indexLocal.get() + 1); return filter; } public void doFilter(HttpFormContentRequestWrapper request, HttpServletResponse response) throws IOException, ServletException { IRequestFilter filter = next(); if (null == filter) { return; } try { filter.doFilter(request, response, this); } catch (Exception e) { e.printStackTrace(); throw e; } } }
MultipleTenantsFilter 做了什么
适用场景
- 同时有请求和应答的场景,例如HTTP请求,数据库查询;
- 映射层转化
- 需要决定是否中断流程的执行;
- 业务的执行分为多个中间环节,中间环节的个数可以定制;
和aop的区别
aop体现的是代理模式,实际是动态代理或 cglib
感想
- 责任链模式,依然符合开闭原则,比如由于业务的发展,需要添加新的逻辑,那么就可以增加一个过滤器,而不用修改原来的逻辑处理;
- 对于逻辑比较复杂,且容易变动的逻辑,可以充分使用责任链模式,把相对聚合的逻辑抽取出来,作为一个个环,后面增加新的逻辑只需要增加新的环即可,也可以根据实际需求修改链条上环的顺序。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Nginx实战案例之Nginx配置SSL证书
本文主要记录Nginx怎么配置SSL证书,前提是Nginx安装成功和SSL证书已经获取。 阿里云安全SSL证书免费申请 在我们下载的证书文件中有一个Nginx的文件夹,这里面的两个文件都是需要的。我们需要把这个两个文件上传到 linux 服务器中,推荐放到/etc/ssl/目录下 然后我们需要去找到nginx的配置文件。 ps -ef | grep nginx 可以看到 nginx的目录是/usr/local/nginx 那么我们需要找到 nginx.conf文件并修改 cd /usr/local/nginx/conf vim nginx.conf 我们需要在 http中去添加一个server节点,如下所示。如果你不习惯在linux中修改,把nginx.conf这个下载到本地修改完成再上传也是一样的。 如果用户使用的是http协议进行访问,那么默认打开的端口是80端口,所以我们需要做一个重定向,我们在上一个代码块的基础上增加一个server节点提供重定向服务。 http{ #http节点中可以添加多个server节点 server{ #监听443端口 listen 443; #对应的域...
- 下一篇
自定义SqlSessionFactoryBean导致 mapper-locations 失效
问题重现 步骤1,把所有的mapper xml移动到 /xxx/yyy/src/main/resources/mybatis/mapperxml 中;2,修改application.properties ,添加: mybatis.mapper-locations=classpath:**/mapperxml/*.xml 3,启动springboot 程序 com/test/xxx/app/nnn/Application.java4,访问接口 http://127.0.0.1:/nnn/productManage/listYYs.json?ccKey=Key222&vvName=%AF%B7%E5%81%87App 报错: org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): 初步分析 根据现象推断出,spring boot 没有读取我的 mybatis mapper xml文件 所以需要找出来,读取mybatis mapper xml文件 的逻辑在哪里,为什么没有读取? ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS6,CentOS7官方镜像安装Oracle11G