阿里巴巴druid源码分析之 filter-chain设计模式

druid是号称目前最好的java数据库连接池,温少写点代码中有很多设计模式的思想,其中最重要的一个就是filter-chain设计模式给druid所带来的可扩展性。对此,我很感兴趣,并希望日后借鉴,所以看了看他的源码,以此记录一下。

druid中设计到filter-chain设计模式的类或接口主要有一下几个Filter、FilterAdapter、FilterChain、FilterChainImpl、FilterEventAdapter、FilterManager 以及举例讲讲两个具体的filter:StatFilter、Slf4jLogFilter

 

具体职责划分如下:

Filter接口:定义了过滤器需要关注的事件,以及可以处理的事件

 

FilterChain接口:定义了这个过滤器链可以处理的事件,druid的设计中,这两个接口几乎一样。

 

FilterChainImpl实现类:主要有两个具体作用,其一,具体处理chain中事件的具体事件;其二,将请求分发给下一个filter‘“处理”,注意,这里的处理,并不是去处理这个事件,而是做一些doBefore,doAfter事件。

 

FilterEventAdapter类:将我们关注的具体事件,通过适配器的设计模式,分为doBefore,do,doAfter三种事件

StatFilter、Slf4jLogFilter类:实现了doBefore,doAfter,这样的话,配置了这两个filter的类就可以做一些切面的事情了

 

FilterManager类:工具类,提供了filter的spi方式加载方式,也在于一种解耦,将filter和chain解耦,方便日后扩展。

 

举例数据库的连接过程

其中filter的接口,每个filter只能临时拥有chain,而每个chain拥有filter:

 ConnectionProxy connection_connect(FilterChain chain, Properties info) throws SQLException;

 FilterChain接口,druid中,最终执行具体方法的是FilterChainImpl,

ConnectionProxy connection_connect(Properties info) throws SQLException;
 int getFilterSize();

 FilterChainImpl具体如何实现调用和分发请求的呢?请看

 public ConnectionProxy connection_connect(Properties info) throws SQLException {
        if (this.pos < filterSize) {
            return nextFilter().connection_connect(this, info);
        }

        Driver driver = dataSource.getRawDriver();
        String url = dataSource.getRawJdbcUrl();

        Connection nativeConnection = driver.connect(url, info);
        return wrap(nativeConnection, info);
    }

 从这里,我们可以看到,其实具体数据库的连接,没必要每个filter都具体去做,为什么呢,因为具体的数据库连接这一步是固定的,写不出花来的,不需要每一个filter去实现,所以,filterChainImpl帮我们做了,这个也是filter-chain和其他的chain不同的地方,它的filter更关注切面的处理。而这里好像也看不出来怎么分发,

请看下面代码:

  private Filter nextFilter() {
        Filter filter = getFilters().get(pos++);
        return filter;
    }

 其实他就是遍历了list,记住list的偏移量,一个个取出来filter的

ok,到这里我们就可以看看filter具体怎样处理事件的。根据上面说的,每个事件被分成了doBefore,do,doAfter那么这是在哪里被切分的呢?这时候就引出了FilterEventAdapter类了

  public ConnectionProxy connection_connect(FilterChain chain, Properties info) throws SQLException {
        connection_connectBefore(chain, info);

        ConnectionProxy connection = super.connection_connect(chain, info);

        connection_connectAfter(connection);

        return connection;
    }

    public void connection_connectBefore(FilterChain chain, Properties info) {

    }

    public void connection_connectAfter(ConnectionProxy connection) {

    }

 看见了吧,这里就被分成了三个事件了,所以,我们可以肯定,每个filter都是继承的FilterEventAdapter

 public ConnectionProxy connection_connect(FilterChain chain, Properties info) throws SQLException {
        ConnectionProxy connection = null;
        {
            long startNano = System.nanoTime();
            long startTime = System.currentTimeMillis();

            long nanoSpan;
            long nowTime = System.currentTimeMillis();

            JdbcDataSourceStat dataSourceStat = chain.getDataSource().getDataSourceStat();
            dataSourceStat.getConnectionStat().beforeConnect();
            try {
                connection = chain.connection_connect(info);
                nanoSpan = System.nanoTime() - startNano;
            } catch (SQLException ex) {
                dataSourceStat.getConnectionStat().connectError(ex);
                throw ex;
            }
            dataSourceStat.getConnectionStat().afterConnected(nanoSpan);

            if (connection != null) {
                JdbcConnectionStat.Entry statEntry = getConnectionInfo(connection);

                dataSourceStat.getConnections().put(connection.getId(), statEntry);

                statEntry.setConnectTime(new Date(startTime));
                statEntry.setConnectTimespanNano(nanoSpan);
                statEntry.setEstablishNano(System.nanoTime());
                statEntry.setEstablishTime(nowTime);
                statEntry.setConnectStackTrace(new Exception());

                dataSourceStat.getConnectionStat().setActiveCount(dataSourceStat.getConnections().size());
            }
        }
        return connection;
    }

 从标红代码中可以看到,果然如此,druid的filter-chain就是这样设计的。FilterManager工具类就不用过多介绍了。

 

 

 

 

本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。

mysql外键实战 - 2016-09-21 14:09:05

一、基本概念 1、MySQL中“键”和“索引”的定义相同,所以外键和主键一样也是索引的一种。不同的是MySQL会自动为所有表的主键进行索引,但是外键字段必须由用户进行明确的索引。用于外键关系的字段必须在所有的参照表中进行明确地索引,InnoDB不能自动地创建索引。 2、外键可以是一对一的,一个表的记录只能与另一个表的一条记录连接,或者是一对多的,一个表的记录与另一个表的多条记录连接。 3、如果需要更好的性能,并且不需要完整性检查,可以选择使用MyISAM表类型,如果想要在MySQL中根据参照完整性来建立表
会联网前沿技术文档,各大公司技术架构,欢迎各位浏览!!!网址: http://dwz.cn/4bwqKb  

Java的文件读写操作 - 2016-09-20 18:09:14

file(内存)----输入流----【程序】----输出流----file(内存) 当我们读写文本文件的时候,采用Reader是非常方便的,比如FileReader,InputStreamReader和BufferedReader。其中最重要的类是InputStreamReader, 它是字节转换为字符的桥梁。你可以在构造器重指定编码的方式,如果不指定的话将采用底层操作系统的默认编码方式,例如GBK等。使用FileReader读取文件: FileReader fr = new FileReader("mi

后端技术杂谈 - 2016-09-20 18:09:07

http://www.rowkey.me/blog/2016/06/27/java-backend-study/?hmsr=toutiao.ioutm_medium=toutiao.ioutm_source=toutiao.io       1、Web Server,Web container和Application Server区别。 Web Server,Web服务器,同上面所说,Web服务器是指能够为发出请求的浏览器提供文档的程序。服务器是一种被动程序,只有浏览器发出请求的时候才会响应。应用层使用的

JSP简单访问数据库 - 2016-09-20 17:09:01

Java代码 public class DBHelper { private String driverName; private String url; private String user; private String password; private Connection connection; private String createTableSql; private String dropTableSql; public void getConnection() { if (null =

微信jsapi扫一扫接口实现(4) - 2016-09-20 14:09:19

微信扫一扫功能在我们日常生活中很常见,那么微信jsapi是如何实现扫一扫功能的呢,接来下给大家详细介绍,并附有代码实现。 微信扫一扫  @V型知识库  原创 调起微信扫一扫接口 1 2 3 4 5 6 7 wx.scanQRCode({      needResult: 0,  // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,      scanType: [ "qrCode" , "barCode" ],  // 可以指定扫二维码还是一维码,默认二者都有      success:  func

mysql操作指令 - 2016-09-19 18:09:09

一、连接mysql   进入 mysql 的安装目录;   $ bin/mysql -p [host IP 如果是登录本地的mysql 可以不写 -p 直接 -u] -u [userName] -p   输入密码,回车,接连; 二、权限操作[如果你很了解mysql数据库后,你可以直接去修改系统表,然后用 mysql flush privileges; 指令让权限生效] 1、赋权   mysqlGRANT ALL[权限名,all 表示所有权限] PRIVILEGES ON [dataBaseName *.*
ws-http.java 好久没有敲过java代码了,今天我家妹纸问我怎么写http post,第一想起来的就是 httpclient,找了下写个简单的东西搞个这么大的库,顺顺觉得杀鸡用牛刀了,记得以前jdk里面是自带httpclient的 sun.net.www.http.HttpClient ,jdk8里面好像移除了,没办法,整个简单的吧,够用就行. 仓库地址:  https://github.com/toohamster/ws-http.java Response httpResponse = ne

XML - JAXP技术 - DOM解析 - 2016-09-19 18:09:12

中秋节刚过去,龙哥布置的几个任务还没做完。唉,又开始学XML了。   DOM解析的基本思路: 1、将整个XML文件一次性读入内存 2、将整个XML看做一棵树 3、XML中的每一个标签,属性,文本都看做是树上的一个结点 4、然后可以对结点进行增删改查的操作   话不多说,上代码。 1、首先我在D:\ABC中新建了一个文本文件,重命名为stus.xml,以下是文件中的内容 ?xml version = "1.0" encoding = "GBK" ? stus class = "S160401A" stu n

java新手入门 - 2016-09-19 17:09:16

java新手入门 Java总有它的千般好处使你选择它,但这些随便翻翻书或在网上逛一圈就能找到答案。在本文中,笔者把自己学习Java的一些切身体会和过程写出来,供Java培训初学者做个参考。 我在学习Java的过程中主要围绕以下几个方面来学习: 1.时刻提醒自己Java是一种OOP语言工具,而不仅仅是编码,只有这样才能总体把握和运用Java。 2.在学习的过程中,最好能够了解Java的底层机制,而不是仅仅停留在表层,不是抄书上的例子运行出结果就可以。要注意,即便对一个简单的例子也要有耐心去琢磨、调试、改动。