写点什么

druid 源码阅读(七)Druid Filter 介绍

  • 2022 年 5 月 16 日
  • 本文字数:1577 字

    阅读完需:约 5 分钟

Druid 连接池最初就是为监控系统采集 jdbc 运行信息而生的,而实现强大的监控能力就是依靠 Filter 实现的,今天就看看 Druid 的 Filter 是如何运行的。

1、Filter 加载

Filter 添加监控可以通过 druidDataSource.addFilters("stat")方式进行添加,是 StatFilter 的别名,这个别名映射配置信息保存在 druid-xxx.jar!/META-INF/druid-filter.properties 中,其中自带的别名配置如下:

druid.filters.default=com.alibaba.druid.filter.stat.StatFilterdruid.filters.stat=com.alibaba.druid.filter.stat.StatFilterdruid.filters.mergeStat=com.alibaba.druid.filter.stat.MergeStatFilterdruid.filters.counter=com.alibaba.druid.filter.stat.StatFilterdruid.filters.encoding=com.alibaba.druid.filter.encoding.EncodingConvertFilterdruid.filters.log4j=com.alibaba.druid.filter.logging.Log4jFilterdruid.filters.log4j2=com.alibaba.druid.filter.logging.Log4j2Filterdruid.filters.slf4j=com.alibaba.druid.filter.logging.Slf4jLogFilterdruid.filters.commonlogging=com.alibaba.druid.filter.logging.CommonsLogFilterdruid.filters.commonLogging=com.alibaba.druid.filter.logging.CommonsLogFilterdruid.filters.wall=com.alibaba.druid.wall.WallFilterdruid.filters.config=com.alibaba.druid.filter.config.ConfigFilterdruid.filters.haRandomValidator=com.alibaba.druid.pool.ha.selector.RandomDataSourceValidateFilter
复制代码

还有一种方式是通过 SPI 的方式,在初始化 DruidDataSource 的时候,会调用 initFromSPIServiceLoader()该方法,该方法会使用 java 的 SPI 机制加载项目中的 Filter,需要注意的是只有被 AutoLoad 注解的才会被真正加载到 DruidDataSource 中。

ServiceLoader<Filter> autoFilterLoader = ServiceLoader.load(Filter.class);for (Filter filter : autoFilterLoader) {    AutoLoad autoLoad = filter.getClass().getAnnotation(AutoLoad.class);    if (autoLoad != null && autoLoad.value()) {        filters.add(filter);    }}
复制代码

2、Filter 接口

查看 Filter 的接口,里面包括 init,destroy,connection_connect,connection_createStatement 等等,覆盖了连接从重建到使用再到关闭的生命周期。

查看 Filter 的实现,发现只有 FilterAdapter 实现了 Filter 的接口,其余的各种 Filter 都是通过继承 FilterAdapter 实现的,官方的解释是:提供 JdbcFilter 的基本实现,使得实现一个 JdbcFilter 更容易。目前我还没有明白为什么要这么设计。

FilterAdapter 实现就是调用 FilterChain 的同名方法。而 FilterChain 只有要给 FilterChain 一个实现类 FilterChainImpl。里面有个关键方法:nextFilter()。该方法只有一行代码:

    private Filter nextFilter() {        return getFilters()                .get(pos++);    }
复制代码


就是获取下一个 Filter。

3、执行过程

以初始化线程池时调用的 Filter 为例,调用 FilterChainImpl 的 dataSource_connect。

filterChain.dataSource_connect(this, maxWaitMillis);
复制代码

dataSource_connect 中的代码如下:

    public DruidPooledConnection dataSource_connect(DruidDataSource dataSource, long maxWaitMillis) throws SQLException {        if (this.pos < filterSize) {            DruidPooledConnection conn = nextFilter().dataSource_getConnection(this, dataSource, maxWaitMillis);            return conn;        }
return dataSource.getConnectionDirect(maxWaitMillis); }
复制代码

这里面的 nextFilter 刚刚说了就是获取下一个 Filter,所以这个方法是调用了下一个 Filter 的 dataSource_getConnection,下一个 Filter 也是这样,每一个 Filter 在调用自己的逻辑之前会先调用一下自己后面的 Filter,所以 Filter 调用是先添加的 Filter 中自己的逻辑会后被调用。

用户头像

还未添加个人签名 2021.05.30 加入

还未添加个人简介

评论

发布
暂无评论
druid 源码阅读(七)Druid Filter 介绍_5月月更_爱晒太阳的大白_InfoQ写作社区