1
0
mirror of https://github.com/drtrang/druid-spring-boot.git synced 2026-09-24 02:35:09 +00:00
This commit is contained in:
trang
2017-11-17 12:37:55 +08:00
parent 16e31536f7
commit 8ec0f4d212
15 changed files with 252 additions and 228 deletions

View File

@@ -1,5 +1,6 @@
package com.github.trang.druid.config;
import lombok.Getter;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
@@ -18,7 +19,7 @@ public class DynamicDataSource extends AbstractRoutingDataSource {
private AtomicInteger count = new AtomicInteger();
private DataSource defaultTargetDataSource;
private Map<String, DataSource> targetDataSources;
@Getter private Map<String, DataSource> targetDataSources;
public DynamicDataSource(DataSource defaultTargetDataSource, Map<String, DataSource> targetDataSources) {
this.defaultTargetDataSource = defaultTargetDataSource;

View File

@@ -1,17 +1,19 @@
package com.github.trang.druid.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.github.trang.druid.autoconfigure.datasource.DruidDataSource2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import static java.util.stream.Collectors.toMap;
/**
* 多数据源配置,只在 #{@code spring.profiles.active=dynamic} 时生效
@@ -23,36 +25,15 @@ import java.util.Map;
@Slf4j
public class SpringDataSourceConfig {
/**
* 第一个数据源,注意数据源类型为 #{@link DruidDataSource2}
*
* `spring.datasource.druid.one` 前缀的配置会注入到该 Bean同时会继承 `spring.datasource.druid`
* 前缀的配置,若名称相同则会被 `spring.datasource.druid.one` 覆盖
*/
@Bean(initMethod = "init", destroyMethod = "close")
@ConfigurationProperties("spring.datasource.druid.data-sources.one")
public DruidDataSource oneDataSource() {
log.debug("druid first-data-source init...");
return new DruidDataSource2();
}
/**
* 第二个数据源,若还有其它数据源可以继续增加
*/
@Bean(initMethod = "init", destroyMethod = "close")
@ConfigurationProperties("spring.datasource.druid.data-sources.two")
public DruidDataSource twoDataSource() {
log.debug("druid second-data-source init...");
return new DruidDataSource2();
}
@Autowired
private List<DruidDataSource> dataSourceList;
@Bean
@Primary
public DynamicDataSource dataSource(DruidDataSource oneDataSource, DruidDataSource twoDataSource) {
Map<String, DataSource> targetDataSources = new HashMap<>(8);
targetDataSources.put(oneDataSource.getName(), oneDataSource);
targetDataSources.put(twoDataSource.getName(), twoDataSource);
return new DynamicDataSource(oneDataSource, targetDataSources);
public DynamicDataSource dataSource() {
Map<String, DataSource> dataSourceMap = dataSourceList.stream()
.collect(toMap(DruidDataSource::getName, Function.identity()));
return new DynamicDataSource(dataSourceMap.get("first"), dataSourceMap);
}
}

View File

@@ -1,18 +0,0 @@
debug: false
spring:
autoconfigure:
exclude:
# 多数据源场景会导致 `javax.sql.DataSource` 和 `org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer`
# 循环依赖,所以需要手动排除 `org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration`
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
datasource:
druid:
# 继承 spring.datasource.druid 前缀的配置,同时可以自定义配置,若名称相同则覆盖父配置
data-sources:
one:
max-active: 50
max-open-prepared-statements: 50
two:
max-active: 25
max-open-prepared-statements: 25

View File

@@ -11,7 +11,7 @@ logging:
spring:
profiles:
# 默认环境为 default多数据源演示请改为 dynamic
active: dynamic
active: default
output:
ansi:
enabled: detect
@@ -77,6 +77,35 @@ mybatis:
---
debug: true
spring:
profiles: default
---
debug: true
spring:
profiles: dynamic
autoconfigure:
exclude:
# 多数据源场景会导致 `javax.sql.DataSource` 和 `org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer`
# 循环依赖,所以需要手动排除 `org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration`
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
datasource:
druid:
# 继承 spring.datasource.druid 前缀的配置,同时可以自定义配置,若名称相同则覆盖父配置
data-sources:
first:
max-active: 50
max-open-prepared-statements: 50
second:
max-active: 25
max-open-prepared-statements: 25
---
debug: false
spring:
@@ -90,60 +119,4 @@ endpoints:
actuator:
enabled: true
druid:
enabled: true
---
debug: false
spring:
profiles: default
---
debug: false
spring:
profiles: dynamic
autoconfigure:
exclude:
# 多数据源场景会导致 `javax.sql.DataSource` 和 `org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer`
# 循环依赖,所以需要手动排除 `org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration`
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
datasource:
druid:
# 继承 spring.datasource.druid 前缀的配置,同时可以自定义配置,若名称相同则覆盖父配置
data-sources:
one:
max-active: 50
max-open-prepared-statements: 50
two:
max-active: 25
max-open-prepared-statements: 25
---
spring:
profiles: dev-yaml
datasource:
druid:
min-evictable-idle-time-millis: 100000
max-evictable-idle-time-millis: 200000
---
spring:
profiles: dynamic-dev-yaml
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
datasource:
druid:
one:
name: one
min-evictable-idle-time-millis: 100001
max-evictable-idle-time-millis: 200001
two:
name: two
min-evictable-idle-time-millis: 100002
max-evictable-idle-time-millis: 200002
enabled: true

View File

@@ -1,28 +0,0 @@
package com.github.trang.druid.test;
import com.alibaba.druid.pool.DruidDataSource;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import static org.junit.Assert.assertEquals;
/**
* 单数据源测试
*
* @author trang
*/
@ActiveProfiles("dev-yaml")
//@ActiveProfiles("dev-props")
public class DevProfilesTests extends BaseTest {
@Autowired
private DruidDataSource dataSource;
@Test
public void testSingleDataSource() {
assertEquals(100000, dataSource.getMinEvictableIdleTimeMillis());
assertEquals(200000, dataSource.getMaxEvictableIdleTimeMillis());
}
}

View File

@@ -1,11 +1,18 @@
package com.github.trang.druid.test;
import com.alibaba.druid.pool.DruidDataSource;
import com.github.trang.druid.autoconfigure.datasource.DruidDataSource2;
import com.github.trang.druid.config.DynamicDataSource;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertEquals;
/**
@@ -57,4 +64,84 @@ public class DynamicDataSourceTests extends BaseTest {
assertEquals(true, secondDataSource.isUseGlobalDataSourceStat());
}
@Test
public void testDynamicDataSource() {
assertEquals(dataSource.getTargetDataSources().size(), 2);
}
@Autowired(required = false)
private Map<String, DruidDataSource> dataSourceMap;
@Autowired(required = false)
private Map<String, DruidDataSource> druidDataSourceMap;
@Autowired(required = false)
private Map<String, DruidDataSource> foolDataSourceMap;
@Autowired(required = false)
private List<DruidDataSource> dataSourceList;
@Autowired(required = false)
private List<DruidDataSource> dataSources;
@Autowired(required = false)
private List<DruidDataSource> druidDataSourceList;
@Autowired(required = false)
private List<DruidDataSource> druidDataSources;
@Autowired(required = false)
private List<DruidDataSource> foolDataSources;
@Autowired(required = false)
private Collection<DruidDataSource> druidDataSourceCollection;
@Autowired(required = false)
private Set<DruidDataSource> druidDataSourceSet;
@Autowired(required = false)
private DruidDataSource[] druidDataSourceArray;
@Autowired(required = false)
private Map<String, DruidDataSource2> dataSource2Map;
@Autowired(required = false)
private Map<String, DruidDataSource2> druidDataSource2Map;
@Autowired(required = false)
private Map<String, DruidDataSource2> foolDataSource2Map;
@Autowired(required = false)
private List<DruidDataSource2> dataSource2List;
@Autowired(required = false)
private List<DruidDataSource2> dataSources2;
@Autowired(required = false)
private List<DruidDataSource2> druidDataSource2List;
@Autowired(required = false)
private List<DruidDataSource2> druidDataSources2;
@Autowired(required = false)
private List<DruidDataSource2> foolDataSources2;
@Autowired(required = false)
private Collection<DruidDataSource2> druidDataSource2Collection;
@Autowired(required = false)
private Set<DruidDataSource2> druidDataSource2Set;
@Autowired(required = false)
private DruidDataSource2[] druidDataSource2Array;
@Test
public void autowire() {
Assert.assertNotNull(dataSourceMap);
Assert.assertNotNull(druidDataSourceMap);
Assert.assertNotNull(foolDataSourceMap);
Assert.assertNotNull(dataSourceList);
Assert.assertNotNull(dataSources);
Assert.assertNotNull(druidDataSourceList);
Assert.assertNotNull(druidDataSources);
Assert.assertNotNull(foolDataSources);
Assert.assertNotNull(druidDataSourceCollection);
Assert.assertNotNull(druidDataSourceSet);
Assert.assertNotNull(druidDataSourceArray);
Assert.assertNotNull(dataSource2Map);
Assert.assertNotNull(druidDataSource2Map);
Assert.assertNotNull(foolDataSource2Map);
Assert.assertNotNull(dataSource2List);
Assert.assertNotNull(dataSources2);
Assert.assertNotNull(druidDataSource2List);
Assert.assertNotNull(druidDataSources2);
Assert.assertNotNull(foolDataSources2);
Assert.assertNotNull(druidDataSource2Collection);
Assert.assertNotNull(druidDataSource2Set);
Assert.assertNotNull(druidDataSource2Array);
}
}

View File

@@ -1,39 +0,0 @@
package com.github.trang.druid.test;
import com.alibaba.druid.pool.DruidDataSource;
import com.github.trang.druid.config.DynamicDataSource;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import static org.junit.Assert.assertEquals;
/**
* 动态数据源测试
*
* @author trang
*/
@ActiveProfiles("dynamic-dev-yaml")
//@ActiveProfiles("dynamic-dev-props")
public class DynamicDevProfilesTests extends BaseTest {
@Autowired
private DruidDataSource firstDataSource;
@Autowired
private DruidDataSource secondDataSource;
@Autowired
private DynamicDataSource dataSource;
@Test
public void testFirstDataSource() {
assertEquals(100001, firstDataSource.getMinEvictableIdleTimeMillis());
assertEquals(200001, firstDataSource.getMaxEvictableIdleTimeMillis());
}
@Test
public void testSecondDataSource() {
assertEquals(100002, secondDataSource.getMinEvictableIdleTimeMillis());
assertEquals(200002, secondDataSource.getMaxEvictableIdleTimeMillis());
}
}

View File

@@ -3,6 +3,7 @@ package com.github.trang.druid.test;
import com.alibaba.druid.pool.DruidDataSource;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import static org.junit.Assert.assertEquals;
@@ -11,6 +12,7 @@ import static org.junit.Assert.assertEquals;
*
* @author trang
*/
@ActiveProfiles("default")
public class SingleDataSourceTests extends BaseTest {
@Autowired

View File

@@ -1,2 +0,0 @@
spring.datasource.druid.min-evictable-idle-time-millis=100000
spring.datasource.druid.max-evictable-idle-time-millis=200000

View File

@@ -1,5 +0,0 @@
spring.autoconfigure.exclude=- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
spring.datasource.druid.one.min-evictable-idle-time-millis=100001
spring.datasource.druid.one.max-evictable-idle-time-millis=200001
spring.datasource.druid.two.min-evictable-idle-time-millis=100002
spring.datasource.druid.two.max-evictable-idle-time-millis=200002

View File

@@ -9,22 +9,34 @@ import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.github.trang.druid.autoconfigure.datasource.DruidDataSource2;
import com.github.trang.druid.autoconfigure.properties.DruidDataSourceProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.bind.PropertySourcesBinder;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.*;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.github.trang.druid.autoconfigure.properties.DruidDataSourceProperties.*;
@@ -39,7 +51,10 @@ import static com.github.trang.druid.autoconfigure.properties.DruidDataSourcePro
@EnableConfigurationProperties({DataSourceProperties.class, DruidDataSourceProperties.class})
@Import({DruidServletConfiguration.class, DruidStatConfiguration.class})
@Slf4j
public class DruidAutoConfiguration implements InitializingBean {
public class DruidAutoConfiguration implements BeanFactoryAware, EnvironmentAware {
private DefaultListableBeanFactory beanFactory;
private ConfigurableEnvironment environment;
@Bean
@ConditionalOnProperty(prefix = DRUID_STAT_FILTER_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
@@ -105,39 +120,101 @@ public class DruidAutoConfiguration implements InitializingBean {
return new CommonsLogFilter();
}
@Autowired
private DefaultListableBeanFactory beanFactory;
@Autowired
private ConfigurableEnvironment environment;
@Autowired
private DruidDataSourceProperties druidDataSourceProperties;
/**
* 自动注入单数据源
*
* @condition 1. BeanFactory 中不存在 DruidDataSource 类型的 bean
* @condition 2. BeanFactory 中不存在 'dataSource' 名称的 bean
* @condition 3. 配置文件中不存在以 'spring.datasource.druid.data-source' 开头的属性
* @return DruidDataSource dataSource
*/
@Bean(initMethod = "init", destroyMethod = "close")
@ConditionalOnMissingBean(value = DataSource.class, name = "dataSource")
@Conditional(DataSourceCondition.class)
public DruidDataSource dataSource() {
log.debug("druid data-source init...");
return new DruidDataSource2();
}
private static final String PRIMARY_DATA_SOURCE_NAME = "dataSource";
private static final String DATA_SOURCE_NAME_SUFFIX = "DataSource";
/**
* 自动注入多数据源
*
* @condition 1. BeanFactory 中不存在 DruidDataSource 类型的 bean
* @condition 2. 配置文件中存在以 'spring.datasource.druid.data-source' 开头的属性
* @return Map dataSourceMap/druidDataSourceMap
*/
@Bean
@Conditional(DataSourcesCondition.class)
public Map<String, DruidDataSource> dataSourceMap(DruidDataSourceProperties druidDataSourceProperties) {
druidDataSourceProperties.getDataSources().forEach((dataSourceName, dataSourceConfig) -> {
// 构造 BeanDefinition通过 DruidDataSource2 实现继承 'spring.datasource.druid' 的配置
BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(DruidDataSource2.class)
.setInitMethodName("init")
.setDestroyMethodName("close")
.getBeanDefinition();
// 注册 BeanDefinition
beanFactory.registerBeanDefinition(dataSourceName, beanDefinition);
// 注册 Alias
beanFactory.registerAlias(dataSourceName, dataSourceName + "DataSource");
// 将 'spring.datasource.druid.data-sources.$dataSourceName' 的配置绑定到 Bean
DruidDataSource2 dataSource = beanFactory.getBean(dataSourceName, DruidDataSource2.class);
PropertySourcesBinder propertySourcesBinder = new PropertySourcesBinder(environment);
propertySourcesBinder.bindTo("spring.datasource.druid.data-sources." + dataSourceName, dataSource);
log.debug("druid {}-data-source init...", dataSourceName);
});
return new HashMap<>(beanFactory.getBeansOfType(DruidDataSource2.class));
}
/**
* 为了便于使用,增加数据源集合,可直接注入使用
* 如需使用 Set、Array 请注入 Set<DruidDataSource2> 或 DruidDataSource2[]
*
* @param dataSourceMap 多数据源
* @return List<DruidDataSource> dataSourceList
*/
@Bean
@ConditionalOnBean(name = "dataSourceMap")
@DependsOn("dataSourceMap")
public List<DruidDataSource> dataSourceList(Map<String, DruidDataSource> dataSourceMap) {
return new ArrayList<>(dataSourceMap.values());
}
static class DataSourceCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(context.getEnvironment(), "spring.datasource.druid.");
Map<String, Object> properties = resolver.getSubProperties("data-sources");
if (!properties.isEmpty()) {
return ConditionOutcome.noMatch("find 'data-sources' properties");
}
return ConditionOutcome.match();
}
}
static class DataSourcesCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(context.getEnvironment(), "spring.datasource.druid.");
Map<String, Object> properties = resolver.getSubProperties("data-sources");
if (properties.isEmpty()) {
return ConditionOutcome.noMatch("can't find 'data-sources' properties");
}
return ConditionOutcome.match();
}
}
@Override
public void afterPropertiesSet() throws Exception {
// if (druidDataSourceProperties.getDataSources().isEmpty() && !beanFactory.containsBean(PRIMARY_DATA_SOURCE_NAME)) {
// BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(DruidDataSource2.class)
// .setInitMethodName("init")
// .setDestroyMethodName("close")
// .getBeanDefinition();
// beanFactory.registerBeanDefinition(PRIMARY_DATA_SOURCE_NAME, beanDefinition);
// log.debug("druid data-source init...");
// } else {
// druidDataSourceProperties.getDataSources().forEach((dataSourceName, dataSourceConfig) -> {
// BeanDefinition eachBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(DruidDataSource2.class)
// .setInitMethodName("init")
// .setDestroyMethodName("close")
// .getBeanDefinition();
// String beanName = dataSourceName + DATA_SOURCE_NAME_SUFFIX;
// beanFactory.registerBeanDefinition(beanName, eachBeanDefinition);
// DruidDataSource2 eachDataSource = beanFactory.getBean(beanName, DruidDataSource2.class);
// PropertySourcesBinder propertySourcesBinder = new PropertySourcesBinder(environment);
// propertySourcesBinder.bindTo("spring.datasource.druid.data-sources." + dataSourceName, eachDataSource);
// log.debug("druid {}-data-source init...", dataSourceName);
// });
// }
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (DefaultListableBeanFactory)beanFactory;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = (ConfigurableEnvironment)environment;
}
}

View File

@@ -29,9 +29,7 @@ import javax.sql.DataSource;
public class DruidDataSourceInitializerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(
type = "org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer",
value = DruidDataSourceInitializer.class)
@ConditionalOnMissingBean(value = DruidDataSourceInitializer.class, name = "dataSourceInitializer")
public DruidDataSourceInitializer dataSourceInitializer(DataSourceProperties properties,
ApplicationContext applicationContext) {
return new DruidDataSourceInitializer(properties, applicationContext);

View File

@@ -1,7 +1,7 @@
package com.github.trang.druid.autoconfigure.datasource;
/**
* Druid 数据源,会继承 `spring.datasource.druid` 配置,并注入 `spring.datasource.druid.${name}` 配置
* Druid 数据源,会继承 DruidDataSource2Support 的配置,并注入 'spring.datasource.druid.data-source.${name}' 的配置
*
* @author trang
*/

View File

@@ -19,7 +19,7 @@ import java.util.Optional;
import static com.github.trang.druid.autoconfigure.properties.DruidDataSourceProperties.DRUID_DATA_SOURCE_PREFIX;
/**
* Druid 多数据源支持,会自动注入 `spring.datasource.druid` 配置
* Druid 多数据源支持,会自动注入 'spring.datasource' 和 'spring.datasource.druid' 配置
*
* @author trang
*/
@@ -30,7 +30,7 @@ public abstract class DruidDataSource2Support extends DruidDataSource {
private DataSourceProperties dataSourceProperties;
@Autowired
private DruidDataSourceProperties druidDataSourceProperties;
@Autowired
@Autowired(required = false)
private List<FilterAdapter> druidFilters;
@PostConstruct

View File

@@ -28,11 +28,8 @@ public class DruidDataSourceProperties {
public static final String DRUID_LOG4J_FILTER_PREFIX = "spring.datasource.druid.log4j";
public static final String DRUID_LOG4J2_FILTER_PREFIX = "spring.datasource.druid.log4j2";
public static final String DRUID_COMMONS_LOG_FILTER_PREFIX = "spring.datasource.druid.commons-log";
public static final String DRUID_CONFIG_FILTER_PREFIX = "spring.datasource.druid.config";
public static final String DRUID_STAT_VIEW_SERVLET_PREFIX = "spring.datasource.druid.stat-view-servlet";
public static final String DRUID_WEB_STAT_PREFIX = "spring.datasource.druid.web-stat";
public static final String DRUID_AOP_STAT_PREFIX = "spring.datasource.druid.aop-stat";