1.动机
很多优良的框架都用到filter,之前的意识比拟含糊,心愿本次有所突破。
2.demo
先入手写一个简略的demo
@Componentpublic class MyFilter extends FilterEventAdapter { @Override protected void statementExecuteBefore(StatementProxy statement, String sql){ System.out.println(sql + "----------MyFilter--------执行开始前!------"); super.statementExecuteBefore(statement,sql); } @Override protected void statementExecuteAfter(StatementProxy statement, String sql, boolean result) { System.out.println(sql + "----------MyFilter--------执行完结后!------"); super.statementExecuteAfter(statement, sql, result); }}
继承FilterEventAdapter,复写俩个办法,打两段日志,代码非常简单。执行测试用例:
@Testvoid insertTest() { String sql = "insert into t_druid_test (id,firstname) " + "VALUES (1,'JINX')"; jdbcTemplate.execute(sql);}
后果如下:
一个简略的自定义filter已实现
3.解析
3.1 Filter
先看filter类图
呃,太长了,看不了...总结一下,针对connection_xxx,resultSet_xxx,statement_xxx,preparedStatement_xxx,callableStatement_xxx,另外还有init,destroy等办法,根本参加了JDBC的全生命周期(datasource->connection->(Prepared)Statement->resultSet),果然是为监控而生。
抽象类FilterAdapter
实现了filter接口,提供了根本的实现,大大减少了反复编码。
FilterEventAdapter
继承FilterAdapter
,在filter的根底上新增了xxxx_before,xxxx_after办法,能够用来做更多的事。
3.2 FilterChain
看类图,接口办法根本和filter统一,次要承当串联filter和传递调用事件的职责。该接口的实现类FilterChainImpl,轻易找一个办法实现看一下:
public ConnectionProxy connection_connect(Properties info) throws SQLException { // 将调用事件一直往下传递,直至this.pos == filterSize if (this.pos < filterSize) { return nextFilter() .connection_connect(this, info); } // 本办法的职责解决 Driver driver = dataSource.getRawDriver(); String url = dataSource.getRawJdbcUrl(); Connection nativeConnection = driver.connect(url, info); if (nativeConnection == null) { return null; } return new ConnectionProxyImpl(dataSource, nativeConnection, info, dataSource.createConnectionId());}
此类的办法根本都是这种构造,分为传递调用和本办法的职责解决。
4.filter如何工作
4.1 初始化
DruidDataSource类init办法中有上面一段代码
for (Filter filter : filters) { filter.init(this);}
4.2 如何工作
对于配置的filter以及自定义的filter都会在此初始化,如果有须要能够持有该datasource的援用。再看一下getConnection办法:
public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException { init(); // init初始化后,filters不会为空 if (filters.size() > 0) { // 初始化chain FilterChainImpl filterChain = new FilterChainImpl(this); return filterChain.dataSource_connect(this, maxWaitMillis); } else { return getConnectionDirect(maxWaitMillis); }}
能够看到,每次调用链中的办法,链总是在调用时初始化。再贴一下connection_connect办法
public DruidPooledConnection dataSource_connect(DruidDataSource dataSource, long maxWaitMillis) throws SQLException { // 将调用事件一直往下传递,直至this.pos == filterSize if (this.pos < filterSize) { DruidPooledConnection conn = nextFilter().dataSource_getConnection(this, dataSource, maxWaitMillis); return conn; } // 本职工作,获取Connection return dataSource.getConnectionDirect(maxWaitMillis); } private Filter nextFilter() { return getFilters() .get(pos++);// 留神这里pos++ }
FilterAdapter类的dataSource_getConnection办法
public DruidPooledConnection dataSource_getConnection(FilterChain chain, DruidDataSource dataSource, long maxWaitMillis) throws SQLException { return chain.dataSource_connect(dataSource, maxWaitMillis);// 将调用关系转接给chain对象,又回到下面的dataSource_connect办法}
贴一下调试截图
- 当this.pos == filterSize时,会执行真正的逻辑
chain通过持有的的Filter对象去调用真正的办法,Filter对象执行时,又将调用关系转接给chain,这样就能一直推动上来
流程图如下:5.参考链接
druid源码钻研之Filter: https://blog.csdn.net/lqzkcx3...
druid 源码剖析与学习(含具体监控设计思路的彩蛋: https://www.iteye.com/blog/he...