之前学习了责任链模式的原理和实现,其本质上来说,就是为了解耦代码应对代码的复杂性,让代码符合开闭原则,提高扩展性
在Web容器的Servlet规范的Servlet Filter和Spring提供的Spring Interceptor中,都是使用了责任链模式去开发的,我们就拿着两个举例说明责任链模式
1.Servlet Filter
Servlet Filter 是Java Servlet规范中的拦截器组件,利用其支持对Http的拦截,比如鉴权,限流,记录等,是Servlet规范的一部分,只要是支持了Servlet规范的Web容器,都会支持Filter过滤器功能
我们去实现一个Servlet Filter
很简单,实现一个实现了Filter接口的实现类即可,并且配置在web.xml配置文件中
Web容器启动的时候,会读取配置文件中的过滤器配置,然后在请求到来的时候,进行处理
public class LogFilter implements Filter {
@Override public void init(FilterConfig filterConfig) throws ServletException { // 在创建Filter时自动调用, // 其中filterConfig包含这个Filter的配置参数,比如name之类的(从配置文件中读取的) } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println(“拦截客户端发送来的请求.”); chain.doFilter(request, response); System.out.println(“拦截发送给客户端的响应.”); } @Override public void destroy() { // 在销毁Filter时自动调用 } } // 在web.xml配置文件中如下配置: <filter> <filter-name>logFilter</filter-name> <filter-class>com.xzg.cd.LogFilter</filter-class> </filter> <filter-mapping> <filter-name>logFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
这样,每次添加过滤器,只需要实现了过滤器类后,在修改配置文件就可以了,这就是利用的责任链设计模式,并且完美符合开闭原则
如何实现的呢?责任链模式的实现需要调用链,处理器组成
对应到Filter中,就是FilterChain和Filter,接下来我们看FilterChain如何实现的
Servlet是一个规范,并不包含具体的实现,所以FilterChain是一个接口定义,真正的实现交给了
具体的容器,例如Tomcat或者Jetty
那么,接下来我们看看Tomcat提供的FilterChain实现类
public final class ApplicationFilterChain implements FilterChain {
private int pos = 0; //当前执行到了哪个filter private int n; //filter的个数 private ApplicationFilterConfig[] filters; private Servlet servlet; @Override public void doFilter(ServletRequest request, ServletResponse response) { if (pos < n) { ApplicationFilterConfig filterConfig = filters[pos++]; Filter filter = filterConfig.getFilter(); filter.doFilter(request, response, this); } else { // filter都处理完毕后,执行servlet servlet.service(request, response); } } public void addFilter(ApplicationFilterConfig filterConfig) { 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; } } 上面当中,doFilter其实是一个递归调用,依次往下调用,然后,在执行完成了Servlet的service函数后,依次返回到顶层 做到了在一个doFilter中既支持入向拦截,也支持了出向拦截 |
2.Spring Interceptor
Spring Interceptor是Spring提供的拦截器,
其基于的Spring MVC框架提供的,由Spring MVC框架实现,一个请求的到处理之前,先经过FIlter在经过拦截器,进行处理,整体流程如下
这个其实和前面Filter类似,只是实现稍有不同,拆分为了两个函数
preHandle()负责去对请求的拦截,相应的拦截则是postHandle()中实现
public class LogInterceptor implements HandlerInterceptor {
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println(“拦截客户端发送来的请求.”); return true; // 继续后续的处理 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println(“拦截发送给客户端的响应.”); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println(“这里总是被执行.”); } } //在Spring MVC配置文件中配置interceptors <mvc:interceptors> <mvc:interceptor> <mvc:mapping path=”/*”/> <bean class=”com.xzg.cd.LogInterceptor” /> </mvc:interceptor> </mvc:interceptors> |
那么,Spring Inteceptor底层如何实现的呢?
其实也是基于的责任链模式去调用的,其中HandlerExecutionChain是其中的责任链模式的处理器链,其职责更加单一,因为在Intercaptor中,被拆分为了入向和出向拦截两个函数去实现的
整体的代码实现如下
public class HandlerExecutionChain {
private final Object handler; private HandlerInterceptor[] interceptors; public void addInterceptor(HandlerInterceptor interceptor) { initInterceptorList().add(interceptor); } boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } } } return true; } void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = interceptors.length – 1; i >= 0; i–) { HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(request, response, this.handler, mv); } } } void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = this.interceptorIndex; i >= 0; i–) { HandlerInterceptor interceptor = interceptors[i]; try { interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable ex2) { logger.error(“HandlerInterceptor.afterCompletion threw exception”, ex2); } } } } } |
在DispatcherServlet的doDispatch()方法去分发请求的时候,会在前后执行HandlerExecutionChain中applyPreHandle()和applyPostHanlde()函数,实现拦截的功能
本章重点
利用拦截器和过滤器功能,让框架的使用者在不修改框架源码的情况下,添加新的过滤拦截功能,符合开闭原则