内容简介:创建型:单例模式,工厂模式,建造者模式,原型模式结构型:桥接模式,代理模式,装饰器模式,适配器模式,门面模式,组合模式,享元模式行为型:观察者模式,模板模式,策略模式,责任链模式,状态模式,迭代器模式,访问者模式
前言
创建型:单例模式,工厂模式,建造者模式,原型模式
结构型:桥接模式,代理模式,装饰器模式,适配器模式,门面模式,组合模式,享元模式
行为型:观察者模式,模板模式,策略模式,责任链模式,状态模式,迭代器模式,访问者模式
介绍
在工作中,我们经常要和Servlet Filter,Spring MVC Interceptor打交道,虽然我配置写的很6,但是出了问题还得到处google,于是看了一下源码,用Demo的方式来分析一下这两者是怎么工作的。
Servlet Filter
Filter的使用
可能很多小伙伴没怎么用过Filter,我就简单演示一下
1.在web.xml中配置2个Filter
<filter-mapping> <filter-name>logFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>imageFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2.实现如下,略去了init方法和destroy方法
@WebFilter(filterName = "logFilter") public class LogFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("LogFilter execute"); chain.doFilter(request, response); } }
@WebFilter(filterName = "imageFilter") public class ImageFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("ImageFilter execute"); chain.doFilter(request, response); } }
3.然后你访问任意一个servlet方法,LogFilter和ImageFilter的doFilter方法都会执行
如果你在一个Filter方法后不加 chain.doFilter(request, response)
则后续的Filter和Servlet都不会执行,这是为什么呢?看完我手写的Demo你一下就明白了
可以看到Filter可以在请求到达Servlet之前做处理,如
- 请求编码
- 敏感词过滤等
有兴趣的小伙伴可以看看相关的源码
手写Filter的实现
Servlet接口,任何一个web请求都会调用service方法
public interface Servlet { public void service(); }
public class MyServlet implements Servlet { @Override public void service() { System.out.println("MyServlet的service方法执行了"); } }
拦截器接口
public interface Filter { public void doFilter(FilterChain chain); }
public class LogFilter implements Filter { @Override public void doFilter(FilterChain chain) { System.out.println("LogFilter执行了"); chain.doFilter(); } }
public class ImageFilter implements Filter { @Override public void doFilter(FilterChain chain) { System.out.println("ImageFilter执行了"); chain.doFilter(); } }
拦截器链对象
public interface FilterChain { public void doFilter(); }
public class ApplicationFilterChain implements FilterChain { private Filter[] filters = new Filter[10]; private Servlet servlet = null; // 总共的Filter数目 private int n; // 当前执行完的filter数目 private int pos; @Override public void doFilter() { if (pos < n) { Filter curFilter = filters[pos++]; curFilter.doFilter(this); return; } servlet.service(); } public void addFilter(Filter filter) { // 这里源码有动态扩容的过程,和ArrayList差不多 // 我就不演示了,直接赋数组大小为10了 filters[n++] = filter; } public void setServlet(Servlet servlet) { this.servlet = servlet; } }
测试例子
public class Main { public static void main(String[] args) { // 在tomcat源码中,会将一个请求封装为一个ApplicationFilterChain对象 // 然后执行ApplicationFilterChain的doFilter方法 ApplicationFilterChain applicationFilterChain = new ApplicationFilterChain(); applicationFilterChain.addFilter(new LogFilter()); applicationFilterChain.addFilter(new ImageFilter()); applicationFilterChain.setServlet(new MyServlet()); // LogFilter执行了 // ImageFilter执行了 // MyServlet的service方法执行了 applicationFilterChain.doFilter(); } }
如果任意一个Filter方法的最后不加上chain.doFilter(),则后面的拦截器及Servlet都不会执行了。相信你看完ApplicationFilterChain类的doFilter方法一下就明白了,就是一个简单的递归调用
Spring MVC Interceptor
Interceptor的使用
以前写过一篇拦截器应用的文章,有想了解使用方式的小伙伴可以看一下
今天就来分析一下拦截器是怎么实现的?可以通过以下方式实现拦截器
- 实现HandlerInterceptor接口
- 继承HandlerInterceptorAdapter抽象类,按需重写部分实现即可,(HandlerInterceptorAdapter也实现了HandlerInterceptor接口)
总而言之拦截器必须必须实现了HandlerInterceptor接口
HandlerInterceptor有如下3个方法
boolean preHandler():在controller执行之前调用
void postHandler():controller执行之后,且页面渲染之前调用
void afterCompletion():页面渲染之后调用,一般用于资源清理操作
这个图应该很好的显示了一个请求可以被拦截的地方
- Servlet Filter是对一个请求到达Servlet的过程进行拦截
- 而HandlerInterceptor是当请求到达DispatcherServlet后,在Controller的方法执行前后进行拦截
手写Interceptor的实现
我来手写一个Demo,你一下就能明白了
拦截接口,为了方便我这里就只定义了一个方法
public interface HandlerInterceptor { boolean preHandle(); }
定义如下2个拦截器
public class CostInterceptor implements HandlerInterceptor { @Override public boolean preHandle() { // 这里可以针对传入的参数做一系列事情,我这里就简单返回true了; System.out.println("CostInterceptor 执行了"); return true; } }
public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle() { System.out.println("LoginInterceptor 执行了"); return true; } }
存放拦截器的容器
public class HandlerExecutionChain { private List<HandlerInterceptor> interceptorList = new ArrayList<>(); public void addInterceptor(HandlerInterceptor interceptor) { interceptorList.add(interceptor); } public boolean applyPreHandle() { for (int i = 0; i < interceptorList.size(); i++) { HandlerInterceptor interceptor = interceptorList.get(i); if (!interceptor.preHandle()) { return false; } } return true; } }
演示DispatcherServlet的调用过程
public class Main { public static void main(String[] args) { // Spring MVC会根据请求返回一个HandlerExecutionChain对象 // 然后执行HandlerExecutionChain的applyPreHandle方法,controller中的方法 HandlerExecutionChain chain = new HandlerExecutionChain(); chain.addInterceptor(new CostInterceptor()); chain.addInterceptor(new LoginInterceptor()); // 只有拦截器都返回true,才会调用controller的方法 // CostInterceptor 执行了 // LoginInterceptor 执行了 if (!chain.applyPreHandle()) { return; } result(); } public static void result() { System.out.println("这是controller的方法"); } }
如果任意一个Interceptor返回false,则后续的Interceptor和Controller中的方法都不会执行原因在Demo中显而易见
当想对请求增加新的过滤逻辑时,只需要定义一个拦截器即可,完全符合开闭原则。
不知道你意识到没有 Servlet Filter和Spring MVC Interceptor都是用责任链模式实现的
来看看DispatcherServlet是怎么做的?和我们上面写的demo一模一样
我们用servlet写web应用时,一个请求地址写一个Servlet类。
而用了spring mvc后,整个应用程序只有一个Servlet即DispatcherServlet,所有的请求都发送到DispatcherServlet,然后通过方法调用的方式执行controller的方法
DispatcherServlet的doDispatch方法源码如下,省略了一部分逻辑(所有的请求都会执行这个方法)
protected void doDispatch() { // 执行所有HandlerInterceptor的preHandle方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 执行controller中的方法 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // 执行所有HandlerInterceptor的postHandle方法 mappedHandler.applyPostHandle(processedRequest, response, mv); }
Interceptor可以有如下用处
- 记录接口响应时间
- 判断用户是否登陆
- 权限校验等
可以看到Servlet Filter和Spring MVC Interceptor都能对请求进行拦截,只不过时机不同。并且Servlet Filter是Servlet的规范,而Spring MVC Interceptor只能在Spring MVC中使用
欢迎关注
参考博客
[0] https://mp.weixin.qq.com/s/8AIRvz5HOgjw12PbsjZhCQ
[1] https://www.cnblogs.com/xrq730/p/10633761.html
filter源码分析
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 惊呆了:我用这个 Go 框架一周实现了一个中台系统
- 惊呆了,RPC超时设置竟然引发了线上事故!
- 坑爹代码 | Stream 玩得最 6 的代码,看过的人都惊呆了
- 惊呆了!不改一行 Java 代码竟然就能轻松解决敏感信息加解密
- 惊呆了!不改一行 Java 代码竟然就能轻松解决敏感信息加解密|原创
- 惊呆了!不改一行 Java 代码竟然就能轻松解决敏感信息加解密|原创
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
CSS 压缩/解压工具
在线压缩/解压 CSS 代码
在线进制转换器
各进制数互转换器