文档章节

责任链模式在典型使用方式

lizo
 lizo
发布于 2017/09/11 10:39
字数 882
阅读 13
收藏 1

责任链模式

责任链模式的定义:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系, 将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止。这里就不再过多的介绍什么是责任链模式,主要来说说java中如何编写。主要从下面3个框架中的代码中介绍。

  • servlet中的filter
  • dubbo中的filter
  • mybatis中的plugin 这3个框架在实现责任链方式不尽相同。

servlet中的Filter

servlet中分别定义了一个 Filter和FilterChain的接口,核心代码如下:

public final class ApplicationFilterChain implements FilterChain {
    private int pos = 0; //当前执行filter的offset
    private int n; //当前filter的数量
    private ApplicationFilterConfig[] filters;  //filter配置类,通过getFilter()方法获取Filter
    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);
        }
    }
 
}

代码还算简单,结构也比较清晰,定义一个Chain,里面包含了Filter列表和servlet,达到在调用真正servlet之前进行各种filter逻辑。

输入图片说明

Dubbo中的Filter

Dubbo在创建Filter的时候是另外一个方法,通过把Filter封装成 Invoker的匿名类,通过链表这样的数据结构来完成责任链,核心代码如下:

private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
    Invoker<T> last = invoker;
    //只获取满足条件的Filter
    List<Filter> 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<T> next = last;
            last = new Invoker<T>() {
                ...
                public Result invoke(Invocation invocation) throws RpcException {
                    return filter.invoke(next, invocation);
                }
                ...
            };
        }
    }
    return last;
}

Dubbo的责任链就没有类似FilterChain这样的类吧Filter和调用Invoker结合起来,而是通过创建一个链表,调用的时候我们只知道第一个节点,每个节点包含了下一个调用的节点信息。 这里的虽然Invoker封装Filter没有显示的指定next,但是通过java匿名类和final的机制达到同样的效果。
输入图片说明

Mybatis中的Plugin

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对责任链模式的不同实现手段,其中Servlet是相对比较清晰,又易于实现的方式,而Dubbo和Mybatis则适合在原有代码基础上,增加责任链模式代码改动量最小的。

© 著作权归作者所有

共有 人打赏支持
lizo
粉丝 58
博文 39
码字总数 48903
作品 0
杭州
程序员
23种设计模式总结(三)

前面2节,我们主要介绍了构建型和结构型的设计模式,今天我们重点讲一下行为型。 策略模式 要点:一个策略的接口,若干个实现类,针对不同的情况,选择不同的策略实现来解决问题。 典型场景:...

大胖和二胖
2016/11/29
7
0
浅析Express中的路由与应用模式

1. 引言 Express是一个基于Node.js的轻量级web开发框架,具有体积小,使用灵活等特点。查看Express的源码,如果不计供使用的中间件,主体框架只有一千余行代码,非常简练。 Express模型的核心...

solarpig
07/16
0
0
23种设计模式总结(一)

总体来说分为3类: 创建型:工厂方法模式、抽象工厂模式、单例、建造者、原型 结构型:适配器、装饰器、代理、外观、桥接、组合、享元 行为型:策略、模板方法、观察者、迭代子、责任链、命令...

大胖和二胖
2016/11/28
11
0
FP角度下的责任链模式(中间件模式,middleware)

责任链模式,十分常见,比如说,j2ee里的filter,express里的middleware,redux里的middleware 问题是:怎么才可以用最简单的方式实现一个责任链模式? 用数组,链表来记录中间件?这些都想过...

m2012
2015/12/10
103
0
用kotlin打印出漂亮的android日志(三)——基于责任链模式打印任意对象

SAF-Kotlin-log 是一个Android的日志框架,这几天我抽空重新更新了一下代码。 github地址:https://github.com/fengzhizi715/SAF-Kotlin-log 一. 打印几个Android常用的对象 1.1 Uri的打印 ...

fengzhizi715
2017/11/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

java并发备忘

不安全的“先检查后执行”,代码形式如下: if(条件满足){ //这里容易出现线程安全问题//doSomething}else{//doOther} 读取-修改-写入 原子操作:使用CAS技术,即首先从V中读取...

Funcy1122
今天
0
0
SpringBoot2.0 停机

最近新建了个SpringBoot2.0的项目,因为原来一直使用的是传统的Tomcat部署war包的形式,所以这次SpringBoot内置Tomcat部署jar包的时候遇到了很多问题。其中一个就是因为没有外置的Tomcat容器...

Canaan_
昨天
0
1
Confluence 6 外部参考

一个外部参考的意思是任何站点链接到你 Confluence 的实例。任何时候当 Confluence 的用户单击这个外部链接的时候,Confluence 可以记录这次单击为参考。 在默认的情况下,外部链接的参考链接...

honeymose
昨天
0
0
Android中的设计模式之抽象工厂模式

参考 《设计模式解析》 第十一章 Abstract Factory模式 《设计模式:可复用面向对象软件的基础 》3.1 Abstract Factory 抽象工厂 对象创建型模式 《Android源码设计模式解析与实战》第6章 创...

newtrek
昨天
0
0
Redis | 地理空间(GEO)的一个坑

Redis的地理空间(Geo)是个好东西,轻轻松松的就可以把地图描点的问题处理了, 最近却遇到一个坑...Redis采用的Msater-Slave模式, 运用GEORADIUS在salve读取对应的数据,新增了从节点但是从不返...

云迹
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部