数据源组件druid filter的扩展机制及spring boot 环境下的几种配置方式

        Druid的监控统计功能是通过filter-chain扩展实现,filter给开发者带来了很好的扩展性,使得我们可以自定义实现一些功能。

在spring boot环境下,除了系统环境变量及jdbc url方式配置filter,大多常用的有以下几种:

(1)在项目中像平时写类加注解的方式

例如:

@Component
public class DemoFilter extends FilterEventAdapter {
    @Override
    public void init(DataSourceProxy dataSource) {
        super.init(dataSource);
    }
}

那这个自定义的filter就自动被注入到DruidDataSource 的filter集合中,要使用这种,实例化DruidDataSource的方式还得借助druid-spring-boot-starter,

@Configuration
public class DataSourceConfig {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Bean(name = "dataSource")
    @ConfigurationProperties("spring.datasource.sdcuike")
    public DataSource dataSource() {
        logger.info("Init DruidDataSource");
        return DruidDataSourceBuilder.create().build();
    }
}

为了和spring boot 融合,用了装饰者模式com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper。使得项目中的所有filter实例自动注入:

 @Autowired(required = false)
    public void autoAddFilters(List<Filter> filters){
        super.filters.addAll(filters);
    }

上述代码使用了spring 的setter注入方式。

(2)实现filter自定义扩展类,并在文件META-INF/druid-filter.properties配置:别名=实现类,并且在数据源属性中配置

spring:
  datasource:
    sdcuike:
      filters: stat,demo3Filter

其扩展思想来源于SPI,其实dubbo的扩展机制也是起源于SPI,在META-INF/druid-filter.properties配置的类会在合适的条件加载类型,并根据配置的别名来决定是不是实例化。

其加载的详细部分代码在com.alibaba.druid.filter.FilterManager#loadFilterConfig(java.util.Properties, java.lang.ClassLoader)

 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);
        }
    }

  别名注入的方式也是通过spring 的setter方式注入的:

com.alibaba.druid.pool.DruidAbstractDataSource#setFilters

    public void setFilters(String filters) throws SQLException {

 

(3)基于java标准的SPI加载机制+注解@AutoLoad 实现

我们需要在文件/src/main/resources/META-INF/services/com.alibaba.druid.filter.Filter,按照java标准的SPI规范配置扩展的filter类型,如com.sdcuike.springboot.druid.filter.Demo2Filter,并且在类上加上注解@AutoLoad即可。

@AutoLoad
public class Demo2Filter extends FilterEventAdapter {
    @Override
    public void init(DataSourceProxy dataSource) {
        super.init(dataSource);
    }
}

其实现代码在com.alibaba.druid.pool.DruidDataSource#initFromSPIServiceLoader

  /**
     * load filters from SPI ServiceLoader
     * 
     * @see ServiceLoader
     */
    private void initFromSPIServiceLoader() {
        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);
        }
    }

以上介绍的三种配置方式,各有优劣。

https://github.com/sdcuike/spring-boot2-practice/tree/druid_filter/src/main/java/com/sdcuike/springboot/druid/filter

发布了296 篇原创文章 · 获赞 178 · 访问量 124万+

猜你喜欢

转载自blog.csdn.net/doctor_who2004/article/details/100066957
今日推荐