一、过滤器的装载
Druid 中过滤器的管理工作,主要是在 FilterManager 类中实现。其中 FilterManager#loadFilter() 负责加载 filter 并放入 filter集合中。
public static void loadFilter(List<Filter> filters, String filterName) throws SQLException {
if (filterName.length() == 0) {
return;
}
// 读取 druid-filter.properties 文件,获取 filterName 对应的过滤器类的名称
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;
}
// 已存在 filterName 对应的过滤器,直接返回
if (existsFilter(filters, filterName)) {
return;
}
// 加载 filterName 对应的过滤器
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);
}
}
其中 getFilter() 方法 会从初始化好的 ConcurrentHashMap——aliasMap 中获取指定的 filter,而 aliasMap 则根据 druid-filter.properties 文件中配的 filter 来初始化。
二、过滤器装载的时机
1. 初始化时——initFromSPIServiceLoader();
private void initFromSPIServiceLoader() {
// 是否跳过装载filter
if (loadSpifilterSkip) {
return;
}
if (autoFilters == null) {
List<Filter> filters = new ArrayList<Filter>();
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);
}
}
autoFilters = filters;
}
for (Filter filter : autoFilters) {
if (LOG.isInfoEnabled()) {
LOG.info("load filter from spi :" + filter.getClass().getName());
}
addFilter(filter);
}
}
2. 获取数据源时
@Override
public Connection connect(String url, Properties info) throws SQLException {
if (!acceptsURL(url)) {
return null;
}
connectCount.incrementAndGet();
// 获取数据源时,会加载 filter:
// FilterManager.loadFilter(config.getFilters(), filterItem);
DataSourceProxyImpl dataSource = getDataSource(url, info);
return dataSource.connect(info);
}
三、filterChain 的使用
从 Druid 连接池获取连接的时候便会使用 nextFilter() 方法从装载 filter 的集合中拿到一个 filter, 并执行这个 filter 的 dataSource_getConnection 方法,将获取到的 DruidPooledConnection 对象依次返回到前面的 filter。这里是一个递归调用,层层下沉,使得可以依次执行 filterchain 的下一个filter,当拿到 DruidPooledConnection 对象,并层层返回时,有一个好处是:返回时每经过一个 filter ,都可以执行 该 filter 的 if (conn != null) {}
里的特殊逻辑。
@Override
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);
}
比如StatFilter#dataSource_connect():
@Override
public DruidPooledConnection dataSource_getConnection(FilterChain chain, DruidDataSource dataSource, long maxWaitMillis) throws SQLException {
// 将调用关系传递到filterchain的下一个filter
DruidPooledConnection conn = chain.dataSource_connect(dataSource, maxWaitMillis);
if (conn != null) {
conn.setConnectedTimeNano();
StatFilterContext.getInstance().pool_connection_open();
}
return conn;
}