【Druid源码阅读】9. 过滤器

Druid源码阅读-filter逻辑浅析 简单看下Druid的Filter实现 阅读详情

在前面几天获取连接的代码中,经常会看到 filters 这个属性,今天一起来看下过滤器是如何工作的。

找一个单侧,把里面连接串和用户名密码改成自己的:

src/test/java/com/alibaba/druid/pool/Case0.java

设置 stat 过滤器

里面有一行代码,就是设置过滤器的:

dataSource.setFilters("stat");
public void setFilters(String filters) throws SQLException {
    // 如果以感叹号 ! 开头,先清除之前设置的所有过滤器(前提是设置了 clearFiltersEnable为 true)
    if (filters != null && filters.startsWith("!")) {
        filters = filters.substring(1);
        this.clearFilters();
    }
    // 添加过滤器
    this.addFilters(filters);
}
public void addFilters(String filters) throws SQLException {
    // 为null或为空字符串,直接返回,不再往下执行
    if (filters == null || filters.length() == 0) {
        return;
    }

    // 使用逗号分隔为数组,即配置多个过滤器可以使用逗号分隔
    String[] filterArray = filters.split("\\,");

    for (String item : filterArray) {
        // 加载过滤器,并保存到 filters 列表中
        FilterManager.loadFilter(this.filters, item.trim());
    }
}

FilterManager 类中有静态代码块,主要逻辑是把过滤器保存到 aliasMap 中:

static {
    try {
        Properties filterProperties = loadFilterConfig();
        for (Map.Entry<Object, Object> entry : filterProperties.entrySet()) {
            String key = (String) entry.getKey();
            if (key.startsWith("druid.filters.")) {
                String name = key.substring("druid.filters.".length());
                aliasMap.put(name, (String) entry.getValue());
            }
        }
    } catch (Throwable e) {
        LOG.error("load filter config error", e);
    }
}


public static Properties loadFilterConfig() throws IOException {
    Properties filterProperties = new Properties();

    // 真正能够加载配置的代码,因为是在当前项目 classpath 下文件中有13项配置,详见下图
    loadFilterConfig(filterProperties, ClassLoader.getSystemClassLoader());
    loadFilterConfig(filterProperties, FilterManager.class.getClassLoader());
    loadFilterConfig(filterProperties, Thread.currentThread().getContextClassLoader());

    return filterProperties;
}

private static void loadFilterConfig(Properties filterProperties, ClassLoader classLoader) throws IOException {
    if (classLoader == null) {
        return;
    }
    
    for (Enumeration<URL> e = classLoader.getResources("META-INF/druid-filter.properties"); e.hasMoreElements();) {
        URL url = e.nextElement();

        Properties property = new Properties();

        InputStream is = null;
        try {
            is = url.openStream();
            property.load(is);
        } finally {
            JdbcUtils.close(is);
        }

        filterProperties.putAll(property);
    }
}

可以看到,从 classpath 路径下找 META-INF/druid-filter.properties 文件进行加载。

然后把 druid.filters. 截断,只保留最后一个单词作为别名,同时也是 aliasMap 的 key。

等静态代码块执行完成后,回到 FilterManager.loadFilter(this.filters, item.trim()); 这个方法中:

public static void loadFilter(List<Filter> filters, String filterName) throws SQLException {
    if (filterName.length() == 0) {
        return;
    }

    String filterClassNames = getFilter(filterName);

    if (filterClassNames != null) {
        for (String filterClassName : filterClassNames.split(",")) {
            if (existsFilter(filters, filterClassName)) {
                continue;
            }
            // 加载过滤器类
            Class<?> filterClass = Utils.loadClass(filterClassName);

            if (filterClass == null) {
                LOG.error("load filter error, filter not found : " + filterClassName);
                continue;
            }

            Filter filter;

            try {
                filter = (Filter) filterClass.newInstance();
            } catch (ClassCastException e) {
                LOG.error("load filter error.", e);
                continue;
            } catch (InstantiationException e) {
                throw new SQLException("load managed jdbc driver event listener error. " + filterName, e);
            } catch (IllegalAccessException e) {
                throw new SQLException("load managed jdbc driver event listener error. " + filterName, e);
            } catch (RuntimeException e) {
                throw new SQLException("load managed jdbc driver event listener error. " + filterName, e);
            }

            filters.add(filter);
        }

        return;
    }

    if (existsFilter(filters, filterName)) {
        return;
    }

    Class<?> filterClass = Utils.loadClass(filterName);
    if (filterClass == null) {
        LOG.error("load filter error, filter not found : " + filterName);
        return;
    }

    try {
        Filter filter = (Filter) filterClass.newInstance();
        filters.add(filter);
    } catch (Exception e) {
        throw new SQLException("load managed jdbc driver event listener error. " + filterName, e);
    }
}

以上把设置的过滤器初始化成对象后,放到了 filters 列表中。

因为配置的是 stat 过滤器,列表中的对象就是 com.alibaba.druid.filter.stat.StatFilter。

过滤器责任链

下面获取连接时,会用到这个过滤器列表:

public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {
    init();

    if (filters.size() > 0) {
        // 如果过滤器列表数量大于0时,构造过滤器责任链
        FilterChainImpl filterChain = new FilterChainImpl(this);
        return filterChain.dataSource_connect(this, maxWaitMillis);
    } else {
        return getConnectionDirect(maxWaitMillis);
    }
}

进入 dataSource_connect 方法

# FilterChainImpl.java
@Override
public DruidPooledConnection dataSource_connect(DruidDataSource dataSource, long maxWaitMillis) throws SQLException {
    if (this.pos < filterSize) {
        // 调用下一个责任链的 dataSource_connect 方法
        DruidPooledConnection conn = nextFilter().dataSource_getConnection(this, dataSource, maxWaitMillis);
        return conn;
    }

    return dataSource.getConnectionDirect(maxWaitMillis);
}

// nextFilter 下一个过滤器
private Filter nextFilter() {
    return getFilters()
            .get(pos++);
}
# StatFilter.java
@Override
public DruidPooledConnection dataSource_getConnection(FilterChain chain, DruidDataSource dataSource, long maxWaitMillis) throws SQLException {

    // 回调责任链的 dataSource_connect 方法
    DruidPooledConnection conn = chain.dataSource_connect(dataSource, maxWaitMillis);

    if (conn != null) {
        conn.setConnectedTimeNano();

        StatFilterContext.getInstance().pool_connection_open();
    }

    return conn;
}

debug可以看到连接被增强了

com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@1a4927d6

今天先看到这里,明天看过滤器的作用和如何发挥作用。 

Spring系列之集成Druid连接池及监控配置 前言 前一篇文章我们熟悉了HikariCP连接池,也了解到它的性能很高,今天我们讲一下另一款比较受欢迎的连接池:Druid,这是阿里开源的一款数据库连接池,它官网上声称:为监控而生!他可以实现页面监控,看到SQL的执行次数、时间和慢SQL信息,也可以对数据库密码信息进行加密,也可以对监控结果进行日志的记录,以及可以实现对敏感操作实现开关,杜绝SQL注入,下面我们详细讲一下它如何与Spring集成,并且顺便了解一下它的监控的配置。 文章要点: Spring集成Druid 监控Filters配置( 阅读详情

相关推荐

【Druid源码阅读】10. 过滤器工作原理

昨天以 StatFilter 分析了责任链模式,今天还以 StatFilter 来举例。 StatFilter 就是用来统计数据,用来支撑 Druid 监控的。 其实大概看一下 StatFilter 的结构,可以看到有很多 public 方法,第一个参数是 FilterChain,并且代码实现都是使用调用过滤器的同名方法, 过滤方法有很多,除了昨天介绍的 dataSource_getConnection,再举个例子: @Override public void connection_commi

hellboy0621的博客 551

druid解析-过滤器详解

我们也可以自定义过滤器。一般过滤器都是继承自FilterAdapter,之后改写其中的部分方法,然后将过滤器名与类名配置到类路径下文件META-INF/druid-filter.properties中,之后在参数“druid.filters”上增加我们自定义的过滤器名就可以了。

龚厂长的博客 6061

Spring Boot 3生产环境数据库密码加密实战:Jasypt+Druid配置详解

在软件工程实践中,配置管理是保障应用安全的重要环节,尤其是数据库密码等敏感信息。对称加密技术通过使用同一密钥进行加密和解密,为配置文件中的敏感数据提供了基础保护层。其技术价值在于防止明文密码泄露,满足生产环境的安全基线要求。应用场景广泛覆盖Spring Boot项目的多环境部署,如开发、测试和生产环境。本文聚焦于Spring Boot 3框架,结合Druid连接池与Jasypt加密库,详细解析如何实现application.yml中数据库密码的自动解密,并深入探讨密钥通过环境变量管理的安全策略,以及Dock

weixin_30825199的博客 444

Druid 内置Filter配置

Druid Spring Boot Starter 对以下 Druid 内置 Filter,都提供了默认配置: StatFilter 通过它可以开启 Druid 的 SQL 监控功能,对 SQL 进行监控。 WallFilter 使用它可以开启防火墙功能,防御 SQL 注入攻击。 ConfigFilter EncodingConvertFilter Slf4jLogFilter Log4jFilter CommonsLogFilter我们可以通过spring.datasource.druid.filter

roydon 1万+

基于SSM框架的线上花店系统:JavaWeb毕业设计与实战部署指南

在JavaWeb开发领域,SSM(Spring、Spring MVC、MyBatis)框架整合是构建企业级应用的核心技术栈,它通过清晰的MVC分层架构实现了业务逻辑、数据持久化和Web请求的高效协同。其技术价值在于为开发者提供了一套标准化、可维护的解决方案,尤其适用于电商、管理等经典业务系统的快速开发。线上花店系统作为一个典型的SSM实战案例,完美诠释了这一技术组合在构建完整业务闭环中的应用,涵盖了从用户端商品浏览、购物车管理到后台订单处理的全流程。对于正在寻找JavaWeb项目练手或准备毕业设计的开发者而

weixin_34242509的博客 409

SpringBoot+Vue学生选课系统:全栈实战项目部署与核心功能解析

在软件开发领域,前后端分离架构已成为构建现代Web应用的主流范式。其核心原理在于将用户界面(前端)与业务逻辑和数据(后端)解耦,通过定义清晰的API接口进行通信。这种架构模式的技术价值在于提升了开发效率、增强了系统的可维护性和可扩展性,并允许前后端团队并行开发。典型的应用场景包括各类管理系统、电商平台以及内容发布系统。本文聚焦于一个基于SpringBoot和Vue技术栈实现的学生选课系统,这是一个典型的**全栈实战项目**,非常适合用于**毕业设计**或作为学习案例。项目提供了从数据库设计到前后端交互的完整

weixin_33739646的博客 435

Druid阅读(一)环境准备

1 下载源代码 访问Druid github地址:https://github.com/alibaba/druid,页面截图如下: 然后选中master分支,点击code->SSH或者HTTPS,复制链接git clone下载即可,页面截图如下: 下载成功后,打开命令行窗口,cd到下载好的Druid的目录下,执行mvn clean package install -Dmaven.test.skip=true -Dmaven.javadoc.skip=true -Drat.skip=true.

he_cha_bu的博客 689

Spring Boot CRM客户关系管理系统:源码剖析与部署实践

客户关系管理系统(CRM)是企业级应用中的典型场景,Spring Boot凭借自动配置与生态优势,成为快速构建此类系统的首选框架。理解CRM的核心在于掌握客户、线索、商机、合同等模块的数据模型与权限设计,这不仅是Java后端开发的基础能力,也是springboot面试题中的高频考点。从开源项目如悟空CRM、芋道源码中学习业务闭环与代码架构,可以大幅提升二次开发效率。同时,系统部署涉及linux部署、环境配置、数据初始化等实操环节,开发者需兼顾开发与运维视角。本文围绕Spring Boot CRM源码,系统讲

weixin_34354173的博客 480

druid1.2.8源码阅读:第三天

druid1.2.8源码阅读:第三天 文章目录druid1.2.8源码阅读:第三天一、创建连接1.1 `init()`方法(1)`JdbcUtils.getDbType`(2)根据DbType设置`cacheServerConfiguration`(4)校验参数设置的是否正确maxActive 连接池中最多支持多少个活动会话useGlobalDataSourceStat 为true的时候,timeBetweenLogStatsMillis 值不能大于0maxEvictableIdleTimeMillis 的

hefrankeleyn的博客 575

基于Java的网络考试系统设计开发与部署全指南

Java Web开发是现代软件工程的基础能力,网络考试系统则是典型的业务闭环实践场景。从Servlet、JSP与MySQL构建的MVC架构出发,理解请求流转、数据持久化、随机组卷、自动评分等核心原理,能够串联起前端交互、后端逻辑与数据库设计的完整知识体系。系统采用多角色权限管理,覆盖题库、试卷、考试、成绩统计全链路,既适合学习分层架构与SQL聚合查询,也能用于毕业设计的实战演练。本文围绕这类管理信息系统的技术选型、表结构设计、环境部署与答辩要点展开,帮助开发者快速上手并完成功能扩展,最终形成一份可运行、可讲

weixin_34184561的博客 517

海康工业相机BayerRG8转BGR8实战:手把手教你用OpenCV实现高效图像转换

本文详细解析了海康工业相机BayerRG8格式到BGR8格式的高效转换实战。针对工业视觉项目中高帧率、大分辨率场景下的性能瓶颈,文章对比了海康SDK原生方案与OpenCV多种转换方法的优劣,并提供了从基础实现到高级优化(如多线程流水线、内存管理、SIMD指令集应用)的完整代码示例与性能调优策略,帮助开发者构建稳定、高效的图像处理系统。

weixin_29237635的博客 522

Druid阅读(三)Druid初始化续

https://blog.csdn.net/he_cha_bu/article/details/121218526https://blog.csdn.net/he_cha_bu/article/details/121218526上一篇文章介绍了druid-spring-boot-starter是如何一步步调用到DruidDataSource的init()方法的,那么今天主要就来分析看看init是如何初始化的。 ...

he_cha_bu的博客 1125

【题解】【中国大学MOOC】(北京大学)人工智能与信息社会考试——期末考试

1.在Alpha-Beta剪枝算法中,我们把一个结点可能取值的上界记作____值,下界记作____值。 编号 选项 A 以上都不对 B Beta,Alpha C Alpha,Beta D Max,Min 2.属于非完全信息博弈的游戏是 编号 选项 A 围棋 B 井字棋 C 军棋 D 黑白棋 3.图中的剪枝过程称为____剪枝 ...

葑鈊丶 1万+

微服务入门:SpringBoot

微服务入门:SpringBoot

qq_59463944的博客 5187

学习记录(十一)--Pattern Recognition投稿记录

上一周特别忽然通知统计建模要答辩,确定是否晋级国赛,一直在准备答辩的事情,所以上一周没有总结周汇报,深刻检讨!!!不过结果是好的,我们组第二名晋级哦。这周主要是跟大家分享一下我投稿PR(Pattern Recognition)的一个时间线,以及投稿后的工作。一、PR从投稿到接收的时间线2025.4.3 Major Revision(ddl4.23) 当时正在弄比赛和另一个着急推进的文章2025.5.30 Minor Revision 这次小修基本上只有一些格式和简单一点点问题。

qq_54949944的博客 1914

Qupath软件的安装与使用

Qupath软件的安装与使用软件安装软件下载软件安装【windows版】简单使用文件打开人工标注标注导出和导入 Qupath是一款开源的医学图像标注软件,适合放射影像及数字病理切片等的查看。同时,其自带的标注功能使得医生可以直接通过该软件进行病变区域的标注和分类。跟进一步的,该软件提供groovy脚本运行接口,可供操作者编写和运行脚本,将标注信息转换为xml或者json格式的数据进行进一步的后序处...

qq_40662074的博客 3万+

SSM框架快递管理系统:从环境搭建到功能测试的完整实践指南

Java Web开发中,SSM(Spring、SpringMVC、MyBatis)框架整合是构建企业级应用的核心技术栈,它通过依赖注入、面向切面编程和MVC分层架构,实现了业务逻辑、数据持久化和Web层的高效解耦与协同。这种架构模式为开发可维护、可扩展的Web系统提供了坚实基础,其技术价值在于规范了开发流程,提升了代码复用性和团队协作效率,广泛应用于电商、物流、OA等各类管理信息系统。本文聚焦于一个典型的快递物流业务场景,通过一个整合了Vue.js前端与MySQL数据库的完整项目,详细拆解了基于SSM框架的

weixin_33835103的博客 309

实战派指南:反激电源EMI滤波器设计,从理论计算到PCB布局避坑

本文详细解析了反激式开关电源EMI滤波器设计的全流程,从理论计算到PCB布局避坑,结合34W PD快充电源案例,系统介绍了共模与差模干扰的识别、关键元件选型、参数计算优化及PCB布局技巧,帮助工程师有效解决传导测试超标等常见问题。

weixin_29230805的博客 373

基于SSM框架的智慧社区停车管理系统:从部署到核心功能测试

Java Web开发是构建企业级应用的核心技术栈,其通过MVC分层架构实现业务逻辑与数据展示的分离。SSM(Spring、Spring MVC、MyBatis)框架整合作为其中的经典实践,提供了依赖注入、请求映射和ORM数据持久化等核心能力,极大地提升了开发效率和系统可维护性。这种技术组合在构建数据驱动的管理系统方面具有显著价值,广泛应用于各类后台管理、信息处理等场景。本文聚焦于一个典型的Java Web毕业设计项目——智慧社区停车管理子系统,详细阐述了如何从零开始部署和验证一个基于SSM框架和MySQL数

weixin_30800807的博客 330

Linux V4L2驱动开发实战:手把手教你用I2C摄像头Sensor注册一个v4l2_subdev

本文详细解析了Linux V4L2驱动开发中I2C摄像头Sensor注册v4l2_subdev的全流程,包括初始化、操作集填充、异步匹配等关键环节。通过实战案例和代码示例,帮助开发者掌握V4L2子系统下的摄像头驱动开发技巧,提升嵌入式Linux系统开发能力。

weixin_30328063的博客 418

别再纠结了!车规MCU选M7还是R52?一张图看懂你的车身控制器/域控制器该用谁

本文深入探讨车规MCU选型中Cortex-M7与Cortex-R52的核心差异,提供基于安全等级与实时性需求的选型决策图。通过对比ASIL认证、实时性能及成本效益,帮助工程师在车身控制器/域控制器设计中做出精准选择,避免潜在风险与隐性成本。

weixin_42628688的博客 397

SpringBoot学生成绩分析系统:毕设实战从部署到答辩

在Java Web开发领域,SpringBoot已成为构建企业级应用的主流框架,它通过自动配置和简化部署,大幅降低了项目搭建成本。学生成绩分析系统正是基于SpringBoot的典型应用,其核心原理是利用分层架构(Controller-Service-Mapper)处理业务逻辑,结合MySQL存储学生、课程、成绩等数据,并通过聚合查询实现统计分析。该系统的技术价值在于模块边界清晰、改造成本低,既能锻炼完整的Web开发能力,又便于在毕业设计或课程设计中快速落地。从实际场景看,它适用于学校教务管理、教师成绩录入与

weixin_33851604的博客 371

Vue3 - Vite运行打包时Uncaught ReferenceError: process is not defined(解决vue3+vite报错process is not defined)

vue3,vite,vue3+vite报错,process,UncaughtReferenceError:processisnotdefined,浏览器控制台报错processisnotdefined解决方法,vue3如何解决报错,vite报错怎么办,前端打包UncaughtReferenceError:processisnotdefined,npmrunbuild打包报错,vite打包时出现错误,vue3打包运行找不到process,热更新会报错UncaughtRefer

🏆 前端领域优质创作者 7737

基于SSM框架的Java智慧社区系统:从环境搭建到二次开发实战指南

在Java Web开发领域,SSM(Spring + Spring MVC + MyBatis)框架组合因其成熟稳定、易于上手的特点,成为构建企业级应用的主流技术选型。其核心原理在于Spring的IoC容器管理对象生命周期,Spring MVC处理Web请求分发,MyBatis实现对象关系映射,共同构建了清晰的分层架构。这套技术栈的价值在于能高效开发数据驱动的管理系统,广泛应用于电商、OA、CRM及各类信息管理平台。本文聚焦于一个典型的应用场景——智慧社区服务系统,详细拆解如何基于SSM框架和MySQL数据

weixin_34055787的博客 359

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

SSM框架Java Web毕业设计:景区信息管理系统部署与开发指南

Java Web开发是构建企业级应用的核心技术,其基于MVC架构实现业务逻辑、数据与表现层的分离。SSM(Spring + Spring MVC + MyBatis)作为经典的Java EE开发框架组合,通过Spring的IoC容器管理对象依赖、Spring MVC处理Web请求、MyBatis简化数据库操作,极大地提升了开发效率和代码可维护性。该技术栈的价值在于为开发者提供了一套标准化、模块化的解决方案,尤其适用于管理信息系统、电商平台等需要复杂业务逻辑和数据持久化的应用场景。本文以景区信息管理系统为例,

weixin_34150830的博客 381

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Spring Boot+Vue学科竞赛导师双向匹配系统:从环境搭建到核心功能测试

在高校信息化建设中,管理系统是连接业务流程与数据的关键枢纽,其核心在于通过前后端分离架构实现高效的数据交互与业务处理。Spring Boot作为主流的Java后端框架,以其快速构建和简化配置的优势,结合Vue.js的响应式前端,构成了现代Web应用开发的主流技术栈。这种架构模式不仅提升了开发效率,更通过RESTful API实现了前后端的解耦,为复杂业务逻辑的实现提供了坚实基础。在教务管理、资源分配等场景中,如何基于预设规则实现资源的智能、公平匹配,是此类系统的重要技术价值所在。本文聚焦的学科竞赛导师双向匹

weixin_30216561的博客 370

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

上一篇: 【Druid源码阅读】7. 驱动加载
下一篇: 【Druid源码阅读】8. 对于连接的管理
hellboy0621
博客等级 码龄9年 61粉丝 147原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值