责任链模式(Chain of Responsibility Pattern),为请求创建一个接收者对象的链,对请求发送者和接收者进行解耦,属于行为型模式。
Servlet API中定义了Filter和FilterChain接口,代码如下:
package javax.servlet;
import java.io.IOException;
public interface FilterChain {
public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException;
}
package javax.servlet;
import java.io.IOException;
/**
* 官方给出的实例如下面这些
* 1) Authentication Filters
* 2) Logging and Auditing Filters
* 3) Image conversion Filters
* 4) Data compression Filters
* 5) Encryption Filters
* 6) Tokenizing Filters
* 7) Filters that trigger resource access events
* 8) XSL/T filters
* 9) Mime-type chain Filter
* @since Servlet 2.3
*/
public interface Filter {
// 初始化方法,实例化的时候执行,只执行一次
public void init(FilterConfig filterConfig) throws ServletException;
// 执行过滤
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
// 销毁方法,容器关闭的时候执行
public void destroy();
}
Tomcat提供了FilterChain的一个实现:ApplicationFilterChain,主要代码片段如下:
// 当前执行filter的offset
private int pos = 0;
// 当前filter的数量
private int n;
//filter配置类,通过getFilter()方法获取Filter
private ApplicationFilterConfig[] filters;
// 最终要执行的Servlet
private Servlet servlet
// 代码做了流程简化,去除了无关的操作
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// 如果还有过滤器,就执行下一个
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
Filter filter = filterConfig.getFilter();
// 此处把过滤器链,也就是当前对象(this)传给过滤器,过滤器执行后又反过来调用这个方法,相互调用构成链
filter.doFilter(request, response, this);
return;
}
// 当过滤器链执行完毕的时候,执行以下代码
// 最终执行的Servlet
servlet.service(request, response);
}
流程如下,这里没有构建实际的链表,只是通过“A->B B->A”的方式来实现责任链。
Dubbo中使用不同的方法,通过把Filter封装成Invoker的匿名类,再构建成责任链,代码如下:
// 类com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
private static Invoker buildInvokerChain(final Invoker invoker, String key, String group) {
Invoker last = invoker;
// 只获取满足条件的Filter
List filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (filters.size() > 0) {
for (int i = filters.size() - 1; i >= 0; i --) {
final Filter filter = filters.get(i);
final Invoker next = last;
last = new Invoker() {
...
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
...
};
}
}
return last;
}
Dubbo则用Invoker把Filter用匿名类的形式封装起来,构建了一条具体的链式结构。
Mybatis可以配置各种Plugin,无论是官方提供的还是自己定义的,Plugin和Filter类似,就在执行Sql语句的时候做一些操作。Mybatis的责任链则是通过动态代理的方式,使用Plugin代理实际的Executor类。(这里实际还使用了组合模式,因为Plugin可以嵌套代理),核心代码如下:
public class Plugin implements InvocationHandler{
private Object target;
private Interceptor interceptor;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (满足代理条件) {
return interceptor.intercept(new Invocation(target, method, args));
}
return method.invoke(target, args);
}
//对传入的对象进行代理,可能是实际的Executor类,也可能是Plugin代理类
public static Object wrap(Object target, Interceptor interceptor) {
Class> type = target.getClass();
Class>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
}
综合三种方式,Servlet是相对比较清晰,又易于实现的方式,而Dubbo和Mybatis则适合在原有代码基础上,增加责任链模式代码改动量最小的。