之前学习了责任链模式的原理和实现,其本质上来说,就是为了解耦代码应对代码的复杂性,让代码符合开闭原则,提高扩展性

在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()函数,实现拦截的功能

本章重点

利用拦截器和过滤器功能,让框架的使用者在不修改框架源码的情况下,添加新的过滤拦截功能,符合开闭原则

发表评论

邮箱地址不会被公开。 必填项已用*标注