This commit is contained in:
trang
2017-07-18 14:44:26 +08:00
parent 6f9ed17ce4
commit 9e0e4d02a2
28 changed files with 896 additions and 377 deletions
+2 -3
View File
@@ -2,8 +2,7 @@
## 1.0.2
1. ~~增加 `WallConfig` 的提示~~
2. 增加 `ConfigFilter` 的配置,替换默认的 ConnectProperties 方式
3. 优化配置项的友好提示
2. ~~增加多数据源支持~~
## 1.0.3
1. 增加读写分离
1. 增加 `ConfigFilter` 的配置,替换默认的 ConnectProperties 方式
+4
View File
@@ -22,6 +22,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
@@ -0,0 +1,30 @@
package com.github.trang.druid;
import com.github.trang.druid.datasource.init.DataSourceInitializer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
/**
* 支持数据源初始化时执行 SQL
*
* 照搬自 #{@link org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer}
*
* 在多数据源场景下,#{@link DataSourceAutoConfiguration} 会报 #{@code DataSource} 和
* #{@code DataSourceInitializer} 的循环依赖,目前的解决办法是排除 #{@link DataSourceAutoConfiguration},
* 但是这样一来,Spring Boot 在数据源初始化时执行 SQL 的特性会被移除,此类是为了保留该特性
*
* @author trang
*/
public class DataSourceInitializerConfiguration {
@Bean
@ConditionalOnMissingBean(DataSourceInitializer.class)
public com.github.trang.druid.datasource.init.DataSourceInitializer dataSourceInitializer
(DataSourceProperties properties, ApplicationContext applicationContext) {
return new DataSourceInitializer(properties, applicationContext);
}
}
@@ -1,6 +1,5 @@
package com.github.trang.druid;
import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.config.ConfigFilter;
import com.alibaba.druid.filter.logging.CommonsLogFilter;
import com.alibaba.druid.filter.logging.Log4j2Filter;
@@ -10,29 +9,24 @@ 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.datasource.DruidParentDataSource;
import com.github.trang.druid.properties.DruidProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
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.util.StringUtils;
import javax.sql.DataSource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
import static com.github.trang.druid.DruidProperties.*;
import static java.util.stream.Collectors.toList;
import static com.github.trang.druid.properties.DruidProperties.*;
/**
* Druid 自动配置
@@ -76,6 +70,7 @@ public class DruidAutoConfiguration {
@ConditionalOnProperty(prefix = DRUID_CONFIG_FILTER_PREFIX, name = "enabled", havingValue = "true")
@Bean
@ConfigurationProperties(DRUID_CONFIG_FILTER_PREFIX)
public ConfigFilter configFilter() {
log.debug("druid config-filter init...");
return new ConfigFilter();
@@ -113,42 +108,11 @@ public class DruidAutoConfiguration {
return new CommonsLogFilter();
}
/*
* 不使用 @Value 注入,避免因为找不到值抛出 NPE
*/
@Autowired
private DataSourceProperties dataSourceProperties;
@ConditionalOnMissingBean(DataSource.class)
@Bean(initMethod = "init", destroyMethod = "close")
@ConfigurationProperties(DRUID_DATA_SOURCE_PREFIX)
public DruidDataSource dataSource(@Autowired(required = false) StatFilter statFilter,
@Autowired(required = false) WallFilter wallFilter,
@Autowired(required = false) ConfigFilter configFilter,
@Autowired(required = false) Slf4jLogFilter slf4jLogFilter,
@Autowired(required = false) Log4jFilter log4jFilter,
@Autowired(required = false) Log4j2Filter log4j2Filter,
@Autowired(required = false) CommonsLogFilter commonsLogFilter) {
public DruidDataSource dataSource() {
log.debug("druid data-source init...");
DruidDataSource dataSource = new DruidDataSource();
if (!StringUtils.isEmpty(dataSourceProperties.getDriverClassName())) {
dataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
}
if (!StringUtils.isEmpty(dataSourceProperties.getUrl())) {
dataSource.setUrl(dataSourceProperties.getUrl());
}
if (!StringUtils.isEmpty(dataSourceProperties.getUsername())) {
dataSource.setUsername(dataSourceProperties.getUsername());
}
if (!StringUtils.isEmpty(dataSourceProperties.getPassword())) {
dataSource.setPassword(dataSourceProperties.getPassword());
}
List<Filter> filters = Stream.of(statFilter, wallFilter, configFilter, slf4jLogFilter, log4jFilter,
log4j2Filter, commonsLogFilter)
.filter(Objects::nonNull)
.collect(toList());
dataSource.setProxyFilters(filters);
return dataSource;
return new DruidParentDataSource() {};
}
}
@@ -1,255 +0,0 @@
package com.github.trang.druid;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import static com.github.trang.druid.DruidProperties.DRUID_DATA_SOURCE_PREFIX;
/**
* Druid 自定义配置
*
* @author trang
*/
@ConfigurationProperties(DRUID_DATA_SOURCE_PREFIX)
public class DruidProperties {
public static final String DRUID_DATA_SOURCE_PREFIX = "spring.datasource.druid";
public static final String DRUID_STAT_FILTER_PREFIX = "spring.datasource.druid.stat";
public static final String DRUID_WALL_FILTER_PREFIX = "spring.datasource.druid.wall";
public static final String DRUID_WALL_CONFIG_PREFIX = "spring.datasource.druid.wall.config";
public static final String DRUID_CONFIG_FILTER_PREFIX = "spring.datasource.druid.config";
public static final String DRUID_SLF4J_FILTER_PREFIX = "spring.datasource.druid.slf4j";
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_WEB_STATE_PREFIX = "spring.datasource.druid.web-stat";
public static final String DRUID_AOP_STAT_PREFIX = "spring.datasource.druid.aop-stat";
public static final String DRUID_STAT_VIEW_SERVLET_PREFIX = "spring.datasource.druid.stat-view-servlet";
@NestedConfigurationProperty
private WebStat webStat = new WebStat();
@NestedConfigurationProperty
private AopStat aopStat = new AopStat();
@NestedConfigurationProperty
private StatViewServlet statViewServlet = new StatViewServlet();
public WebStat getWebStat() {
return webStat;
}
public void setWebStat(WebStat webStat) {
this.webStat = webStat;
}
public AopStat getAopStat() {
return aopStat;
}
public void setAopStat(AopStat aopStat) {
this.aopStat = aopStat;
}
public StatViewServlet getStatViewServlet() {
return statViewServlet;
}
public void setStatViewServlet(StatViewServlet statViewServlet) {
this.statViewServlet = statViewServlet;
}
/**
* WebStat 自定义配置
*
* @author trang
*/
public static class WebStat {
// 是否开启 web-jdbc 监控,默认否
private boolean enabled;
// 过滤器 url 的映射规则
private String urlPatterns = "/*";
// 过滤器 url 的排除规则
private String exclusions = "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*";
// 是否开启 session 统计,默认否
private boolean sessionStatEnable;
// session 统计的最大值,默认值 1000
private Integer sessionStatMaxCount = 1000;
// 配置当前 session 的用户
private String principalSessionName;
// 配置当前 cookie 的用户
private String principalCookieName;
// 是否开启监控单个 url 调用的 sql 列表,默认是
private boolean profileEnable = true;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getUrlPatterns() {
return urlPatterns;
}
public void setUrlPatterns(String urlPatterns) {
this.urlPatterns = urlPatterns;
}
public String getExclusions() {
return exclusions;
}
public void setExclusions(String exclusions) {
this.exclusions = exclusions;
}
public boolean isSessionStatEnable() {
return sessionStatEnable;
}
public void setSessionStatEnable(boolean sessionStatEnable) {
this.sessionStatEnable = sessionStatEnable;
}
public Integer getSessionStatMaxCount() {
return sessionStatMaxCount;
}
public void setSessionStatMaxCount(Integer sessionStatMaxCount) {
this.sessionStatMaxCount = sessionStatMaxCount;
}
public String getPrincipalSessionName() {
return principalSessionName;
}
public void setPrincipalSessionName(String principalSessionName) {
this.principalSessionName = principalSessionName;
}
public String getPrincipalCookieName() {
return principalCookieName;
}
public void setPrincipalCookieName(String principalCookieName) {
this.principalCookieName = principalCookieName;
}
public boolean isProfileEnable() {
return profileEnable;
}
public void setProfileEnable(boolean profileEnable) {
this.profileEnable = profileEnable;
}
}
/**
* Aop 监控自定义配置
*/
public static class AopStat {
// 是否开启基于 aop 的监控,默认否
private boolean enabled;
// aop 拦截规则
private String[] patterns;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String[] getPatterns() {
return patterns;
}
public void setPatterns(String[] patterns) {
this.patterns = patterns;
}
}
/**
* StatViewServlet 自定义配置
*
* @author trang
*/
public static class StatViewServlet {
// 是否开启 Druid 的数据统计页面,默认否
private boolean enabled= false;
// Servlet 的映射规则,默认访问 "http://xxx/druid/"
private String urlMappings = "/druid/*";
// Druid 统计页面的登陆用户名
private String loginUsername;
// Druid 统计页面的登陆密码
private String loginPassword;
// Druid 统计页面的访问白名单,默认允许所有人访问
private String allow;
// Druid 统计页面的访问黑名单,优先于白名单
private String deny;
// 是否允许清空统计数据,默认否
private boolean resetEnable;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getUrlMappings() {
return urlMappings;
}
public void setUrlMappings(String urlMappings) {
this.urlMappings = urlMappings;
}
public String getLoginUsername() {
return loginUsername;
}
public void setLoginUsername(String loginUsername) {
this.loginUsername = loginUsername;
}
public String getLoginPassword() {
return loginPassword;
}
public void setLoginPassword(String loginPassword) {
this.loginPassword = loginPassword;
}
public String getAllow() {
return allow;
}
public void setAllow(String allow) {
this.allow = allow;
}
public String getDeny() {
return deny;
}
public void setDeny(String deny) {
this.deny = deny;
}
public boolean isResetEnable() {
return resetEnable;
}
public void setResetEnable(boolean resetEnable) {
this.resetEnable = resetEnable;
}
}
}
@@ -1,15 +1,17 @@
package com.github.trang.druid;
import com.alibaba.druid.support.http.StatViewServlet;
import com.github.trang.druid.properties.DruidServletProperties.DruidStatViewServletProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.util.StringUtils;
import static com.github.trang.druid.DruidProperties.DRUID_STAT_VIEW_SERVLET_PREFIX;
import static com.github.trang.druid.properties.DruidServletProperties.DRUID_STAT_VIEW_SERVLET_PREFIX;
/**
* Druid Servlet 配置
@@ -17,6 +19,7 @@ import static com.github.trang.druid.DruidProperties.DRUID_STAT_VIEW_SERVLET_PRE
* @author trang
*/
@ConditionalOnWebApplication
@EnableConfigurationProperties(DruidStatViewServletProperties.class)
public class DruidServletConfiguration {
private static final Logger log = LoggerFactory.getLogger(DruidServletConfiguration.class);
@@ -24,31 +27,30 @@ public class DruidServletConfiguration {
/**
* Druid 提供了一个 StatViewServlet 用于展示 Druid 的统计信息
* 这个 StatViewServlet 的用途包括:
* 1. 提供监控信息展示的 HTML 页面
* 2. 提供监控信息的 JSON API
* 1. 提供监控信息展示的 HTML 页面
* 2. 提供监控信息的 JSON API
*/
@ConditionalOnProperty(prefix = DRUID_STAT_VIEW_SERVLET_PREFIX, name = "enabled", havingValue = "true")
@Bean
public ServletRegistrationBean servletRegistrationBean(DruidProperties properties) {
public ServletRegistrationBean servletRegistrationBean(DruidStatViewServletProperties properties) {
log.debug("druid stat-view-servlet init...");
ServletRegistrationBean registration = new ServletRegistrationBean();
DruidProperties.StatViewServlet config = properties.getStatViewServlet();
StatViewServlet statViewServlet = new StatViewServlet();
registration.setServlet(statViewServlet);
registration.addUrlMappings(config.getUrlMappings());
if (!StringUtils.isEmpty(config.getLoginUsername())) {
registration.addInitParameter("loginUsername", config.getLoginUsername());
registration.addUrlMappings(properties.getUrlMappings());
if (!StringUtils.isEmpty(properties.getLoginUsername())) {
registration.addInitParameter("loginUsername", properties.getLoginUsername());
}
if (!StringUtils.isEmpty(config.getLoginPassword())) {
registration.addInitParameter("loginPassword", config.getLoginPassword());
if (!StringUtils.isEmpty(properties.getLoginPassword())) {
registration.addInitParameter("loginPassword", properties.getLoginPassword());
}
if (!StringUtils.isEmpty(config.getAllow())) {
registration.addInitParameter("allow", config.getAllow());
if (!StringUtils.isEmpty(properties.getAllow())) {
registration.addInitParameter("allow", properties.getAllow());
}
if (!StringUtils.isEmpty(config.getDeny())) {
registration.addInitParameter("deny", config.getDeny());
if (!StringUtils.isEmpty(properties.getDeny())) {
registration.addInitParameter("deny", properties.getDeny());
}
registration.addInitParameter("resetEnable", Boolean.toString(config.isResetEnable()));
registration.addInitParameter("resetEnable", Boolean.toString(properties.isResetEnable()));
return registration;
}
@@ -2,7 +2,8 @@ package com.github.trang.druid;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
import com.github.trang.druid.DruidProperties.WebStat;
import com.github.trang.druid.properties.DruidStatProperties.DruidAopStatProperties;
import com.github.trang.druid.properties.DruidStatProperties.DruidWebStatProperties;
import org.aopalliance.aop.Advice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -12,18 +13,20 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.util.StringUtils;
import static com.github.trang.druid.DruidProperties.DRUID_AOP_STAT_PREFIX;
import static com.github.trang.druid.DruidProperties.DRUID_WEB_STATE_PREFIX;
import static com.github.trang.druid.properties.DruidStatProperties.DRUID_AOP_STAT_PREFIX;
import static com.github.trang.druid.properties.DruidStatProperties.DRUID_WEB_STAT_PREFIX;
/**
* Druid 监控配置
*
* @author trang
*/
@EnableConfigurationProperties({DruidWebStatProperties.class, DruidAopStatProperties.class})
public class DruidStatConfiguration {
/**
@@ -44,9 +47,9 @@ public class DruidStatConfiguration {
}
@Bean
public RegexpMethodPointcutAdvisor druidStatAdvisor(DruidProperties druidProperties,
public RegexpMethodPointcutAdvisor druidStatAdvisor(DruidAopStatProperties properties,
DruidStatInterceptor druidStatInterceptor) {
return new RegexpMethodPointcutAdvisor(druidProperties.getAopStat().getPatterns(), druidStatInterceptor);
return new RegexpMethodPointcutAdvisor(properties.getPatterns(), druidStatInterceptor);
}
@Bean
@@ -67,27 +70,26 @@ public class DruidStatConfiguration {
private static final Logger log = LoggerFactory.getLogger(DruidStatConfiguration.class);
@ConditionalOnProperty(prefix = DRUID_WEB_STATE_PREFIX, name = "enabled", havingValue = "true")
@ConditionalOnProperty(prefix = DRUID_WEB_STAT_PREFIX, name = "enabled", havingValue = "true")
@Bean
public FilterRegistrationBean filterRegistrationBean(DruidProperties properties) {
public FilterRegistrationBean filterRegistrationBean(DruidWebStatProperties properties) {
log.debug("druid web-stat-filter init...");
FilterRegistrationBean registration = new FilterRegistrationBean();
WebStat config = properties.getWebStat();
WebStatFilter filter = new WebStatFilter();
registration.setFilter(filter);
registration.addUrlPatterns(config.getUrlPatterns());
registration.addInitParameter("exclusions", config.getExclusions());
registration.addInitParameter("sessionStatEnable", Boolean.toString(config.isSessionStatEnable()));
if (!StringUtils.isEmpty(config.getSessionStatMaxCount())) {
registration.addInitParameter("sessionStatMaxCount",Integer.toString(config.getSessionStatMaxCount()));
registration.addUrlPatterns(properties.getUrlPatterns());
registration.addInitParameter("exclusions", properties.getExclusions());
registration.addInitParameter("sessionStatEnable", Boolean.toString(properties.isSessionStatEnable()));
if (!StringUtils.isEmpty(properties.getSessionStatMaxCount())) {
registration.addInitParameter("sessionStatMaxCount",Integer.toString(properties.getSessionStatMaxCount()));
}
if (!StringUtils.isEmpty(config.getPrincipalSessionName())) {
registration.addInitParameter("principalSessionName", config.getPrincipalSessionName());
if (!StringUtils.isEmpty(properties.getPrincipalSessionName())) {
registration.addInitParameter("principalSessionName", properties.getPrincipalSessionName());
}
if (!StringUtils.isEmpty(config.getPrincipalCookieName())) {
registration.addInitParameter("principalCookieName", config.getPrincipalCookieName());
if (!StringUtils.isEmpty(properties.getPrincipalCookieName())) {
registration.addInitParameter("principalCookieName", properties.getPrincipalCookieName());
}
registration.addInitParameter("profileEnable", Boolean.toString(config.isProfileEnable()));
registration.addInitParameter("profileEnable", Boolean.toString(properties.isProfileEnable()));
return registration;
}
@@ -0,0 +1,10 @@
package com.github.trang.druid.datasource;
/**
* Druid 多数据源支持,支持共用公共参数
*
* @author trang
*/
public class DruidMultiDataSource extends DruidParentDataSource {
}
@@ -0,0 +1,72 @@
package com.github.trang.druid.datasource;
import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.config.ConfigFilter;
import com.alibaba.druid.filter.logging.CommonsLogFilter;
import com.alibaba.druid.filter.logging.Log4j2Filter;
import com.alibaba.druid.filter.logging.Log4jFilter;
import com.alibaba.druid.filter.logging.Slf4jLogFilter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.wall.WallFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
import static com.github.trang.druid.properties.DruidProperties.DRUID_DATA_SOURCE_PREFIX;
/**
* Druid 多数据源支持,支持共用公共参数
*
* @author trang
*/
@ConfigurationProperties(DRUID_DATA_SOURCE_PREFIX)
public abstract class DruidParentDataSource extends DruidDataSource {
@Autowired(required = false)
private StatFilter statFilter;
@Autowired(required = false)
private WallFilter wallFilter;
@Autowired(required = false)
private ConfigFilter configFilter;
@Autowired(required = false)
private Slf4jLogFilter slf4jLogFilter;
@Autowired(required = false)
private Log4jFilter log4jFilter;
@Autowired(required = false)
private Log4j2Filter log4j2Filter;
@Autowired(required = false)
private CommonsLogFilter commonsLogFilter;
// 不使用 @Value 注入,避免因为找不到值抛出 NPE
@Autowired
private DataSourceProperties dataSourceProperties;
@PostConstruct
public void initCommonParams() {
if (!StringUtils.isEmpty(dataSourceProperties.getDriverClassName())) {
super.setDriverClassName(dataSourceProperties.getDriverClassName());
}
if (!StringUtils.isEmpty(dataSourceProperties.getUrl())) {
super.setUrl(dataSourceProperties.getUrl());
}
if (!StringUtils.isEmpty(dataSourceProperties.getUsername())) {
super.setUsername(dataSourceProperties.getUsername());
}
if (!StringUtils.isEmpty(dataSourceProperties.getPassword())) {
super.setPassword(dataSourceProperties.getPassword());
}
List<Filter> filters = super.getProxyFilters();
Stream.of(statFilter, wallFilter, configFilter, slf4jLogFilter, log4jFilter, log4j2Filter,
commonsLogFilter)
.filter(Objects::nonNull)
.filter(filter -> !filters.contains(filter))
.forEach(filters::add);
}
}
@@ -0,0 +1,177 @@
package com.github.trang.druid.datasource.init;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.autoconfigure.jdbc.DataSourceInitializedEvent;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.config.ResourceNotFoundException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.config.SortedResourcesFactoryBean;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Bean to handle {@link DataSource} initialization by running {@literal schema-*.sql} on
* {@link PostConstruct} and {@literal data-*.sql} SQL scripts on a
* {@link DataSourceInitializedEvent}.
*
* @author Dave Syer
* @author Phillip Webb
* @author Eddú Meléndez
* @author Stephane Nicoll
* @author Kazuki Shimizu
* @since 1.1.0
* @see com.github.trang.druid.DataSourceInitializerConfiguration
*/
public class DataSourceInitializer implements ApplicationListener<DataSourceInitializedEvent> {
private static final Logger logger = LoggerFactory.getLogger(DataSourceInitializer.class);
private final DataSourceProperties properties;
private final ApplicationContext applicationContext;
private DataSource dataSource;
private boolean initialized = false;
public DataSourceInitializer(DataSourceProperties properties,
ApplicationContext applicationContext) {
this.properties = properties;
this.applicationContext = applicationContext;
}
@PostConstruct
public void init() {
if (!this.properties.isInitialize()) {
logger.debug("Initialization disabled (not running DDL scripts)");
return;
}
if (this.applicationContext.getBeanNamesForType(DataSource.class, false,
false).length > 0) {
this.dataSource = this.applicationContext.getBean(DataSource.class);
}
if (this.dataSource == null) {
logger.debug("No DataSource found so not initializing");
return;
}
runSchemaScripts();
}
private void runSchemaScripts() {
List<Resource> scripts = getScripts("spring.datasource.schema",
this.properties.getSchema(), "schema");
if (!scripts.isEmpty()) {
String username = this.properties.getSchemaUsername();
String password = this.properties.getSchemaPassword();
runScripts(scripts, username, password);
try {
this.applicationContext
.publishEvent(new DataSourceInitializedEvent(this.dataSource));
// The listener might not be registered yet, so don't rely on it.
if (!this.initialized) {
runDataScripts();
this.initialized = true;
}
} catch (IllegalStateException ex) {
logger.warn("Could not send event to complete DataSource initialization ("
+ ex.getMessage() + ")");
}
}
}
@Override
public void onApplicationEvent(DataSourceInitializedEvent event) {
if (!this.properties.isInitialize()) {
logger.debug("Initialization disabled (not running data scripts)");
return;
}
// NOTE the event can happen more than once and
// the event datasource is not used here
if (!this.initialized) {
runDataScripts();
this.initialized = true;
}
}
private void runDataScripts() {
List<Resource> scripts = getScripts("spring.datasource.data",
this.properties.getData(), "data");
String username = this.properties.getDataUsername();
String password = this.properties.getDataPassword();
runScripts(scripts, username, password);
}
private List<Resource> getScripts(String propertyName, List<String> resources,
String fallback) {
if (resources != null) {
return getResources(propertyName, resources, true);
}
String platform = this.properties.getPlatform();
List<String> fallbackResources = new ArrayList<String>();
fallbackResources.add("classpath*:" + fallback + "-" + platform + ".sql");
fallbackResources.add("classpath*:" + fallback + ".sql");
return getResources(propertyName, fallbackResources, false);
}
private List<Resource> getResources(String propertyName, List<String> locations,
boolean validate) {
List<Resource> resources = new ArrayList<Resource>();
for (String location : locations) {
for (Resource resource : doGetResources(location)) {
if (resource.exists()) {
resources.add(resource);
} else if (validate) {
throw new ResourceNotFoundException(propertyName, resource);
}
}
}
return resources;
}
private Resource[] doGetResources(String location) {
try {
SortedResourcesFactoryBean factory = new SortedResourcesFactoryBean(
this.applicationContext, Collections.singletonList(location));
factory.afterPropertiesSet();
return factory.getObject();
} catch (Exception ex) {
throw new IllegalStateException("Unable to load resources from " + location,
ex);
}
}
private void runScripts(List<Resource> resources, String username, String password) {
if (resources.isEmpty()) {
return;
}
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
populator.setContinueOnError(this.properties.isContinueOnError());
populator.setSeparator(this.properties.getSeparator());
if (this.properties.getSqlScriptEncoding() != null) {
populator.setSqlScriptEncoding(this.properties.getSqlScriptEncoding().name());
}
for (Resource resource : resources) {
populator.addScript(resource);
}
DataSource dataSource = this.dataSource;
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
dataSource = DataSourceBuilder.create(this.properties.getClassLoader())
.driverClassName(this.properties.determineDriverClassName())
.url(this.properties.determineUrl()).username(username)
.password(password).build();
}
DatabasePopulatorUtils.execute(populator, dataSource);
}
}
@@ -0,0 +1,20 @@
package com.github.trang.druid.properties;
/**
* Druid 自定义配置
*
* @author trang
*/
public class DruidProperties {
public static final String DRUID_DATA_SOURCE_PREFIX = "spring.datasource.druid";
public static final String DRUID_STAT_FILTER_PREFIX = "spring.datasource.druid.stat";
public static final String DRUID_WALL_FILTER_PREFIX = "spring.datasource.druid.wall";
public static final String DRUID_WALL_CONFIG_PREFIX = "spring.datasource.druid.wall.config";
public static final String DRUID_CONFIG_FILTER_PREFIX = "spring.datasource.druid.config";
public static final String DRUID_SLF4J_FILTER_PREFIX = "spring.datasource.druid.slf4j";
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";
}
@@ -0,0 +1,95 @@
package com.github.trang.druid.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Druid 数据展示配置
*
* @author trang
*/
public class DruidServletProperties {
public static final String DRUID_STAT_VIEW_SERVLET_PREFIX = "spring.datasource.druid.stat-view-servlet";
/**
* StatViewServlet 自定义配置
*
* @author trang
*/
@ConfigurationProperties(DRUID_STAT_VIEW_SERVLET_PREFIX)
public static class DruidStatViewServletProperties {
// 是否开启 Druid 的数据统计页面,默认否
private boolean enabled;
// Servlet 的映射规则,默认访问 "http://xxx/druid/"
private String urlMappings = "/druid/*";
// Druid 统计页面的登陆用户名
private String loginUsername;
// Druid 统计页面的登陆密码
private String loginPassword;
// Druid 统计页面的访问白名单,默认允许所有人访问
private String allow;
// Druid 统计页面的访问黑名单,优先于白名单
private String deny;
// 是否允许清空统计数据,默认否
private boolean resetEnable;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getUrlMappings() {
return urlMappings;
}
public void setUrlMappings(String urlMappings) {
this.urlMappings = urlMappings;
}
public String getLoginUsername() {
return loginUsername;
}
public void setLoginUsername(String loginUsername) {
this.loginUsername = loginUsername;
}
public String getLoginPassword() {
return loginPassword;
}
public void setLoginPassword(String loginPassword) {
this.loginPassword = loginPassword;
}
public String getAllow() {
return allow;
}
public void setAllow(String allow) {
this.allow = allow;
}
public String getDeny() {
return deny;
}
public void setDeny(String deny) {
this.deny = deny;
}
public boolean isResetEnable() {
return resetEnable;
}
public void setResetEnable(boolean resetEnable) {
this.resetEnable = resetEnable;
}
}
}
@@ -0,0 +1,135 @@
package com.github.trang.druid.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Druid 监控配置
*
* @author trang
*/
public class DruidStatProperties {
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";
/**
* WebStat 自定义配置
*
* @author trang
*/
@ConfigurationProperties(DRUID_WEB_STAT_PREFIX)
public static class DruidWebStatProperties {
// 是否开启 web-jdbc 监控,默认否
private boolean enabled;
// 过滤器 url 的映射规则
private String urlPatterns = "/*";
// 过滤器 url 的排除规则
private String exclusions = "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*";
// 是否开启 session 统计,默认否
private boolean sessionStatEnable;
// session 统计的最大值,默认值 1000
private Integer sessionStatMaxCount = 1000;
// 配置当前 session 的用户
private String principalSessionName;
// 配置当前 cookie 的用户
private String principalCookieName;
// 是否开启监控单个 url 调用的 sql 列表,默认是
private boolean profileEnable = true;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getUrlPatterns() {
return urlPatterns;
}
public void setUrlPatterns(String urlPatterns) {
this.urlPatterns = urlPatterns;
}
public String getExclusions() {
return exclusions;
}
public void setExclusions(String exclusions) {
this.exclusions = exclusions;
}
public boolean isSessionStatEnable() {
return sessionStatEnable;
}
public void setSessionStatEnable(boolean sessionStatEnable) {
this.sessionStatEnable = sessionStatEnable;
}
public Integer getSessionStatMaxCount() {
return sessionStatMaxCount;
}
public void setSessionStatMaxCount(Integer sessionStatMaxCount) {
this.sessionStatMaxCount = sessionStatMaxCount;
}
public String getPrincipalSessionName() {
return principalSessionName;
}
public void setPrincipalSessionName(String principalSessionName) {
this.principalSessionName = principalSessionName;
}
public String getPrincipalCookieName() {
return principalCookieName;
}
public void setPrincipalCookieName(String principalCookieName) {
this.principalCookieName = principalCookieName;
}
public boolean isProfileEnable() {
return profileEnable;
}
public void setProfileEnable(boolean profileEnable) {
this.profileEnable = profileEnable;
}
}
/**
* Aop 监控自定义配置
*/
@ConfigurationProperties(DRUID_AOP_STAT_PREFIX)
public static class DruidAopStatProperties {
// 是否开启基于 aop 的监控,默认否
private boolean enabled;
// aop 拦截规则
private String[] patterns;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String[] getPatterns() {
return patterns;
}
public void setPatterns(String[] patterns) {
this.patterns = patterns;
}
}
}
@@ -3,64 +3,64 @@
{
"name": "spring.datasource.druid.stat.enabled",
"type": "java.lang.Boolean",
"description": "Whether or not druid stat filter are enabled.",
"description": "Whether or not druid stat-filter are enabled.",
"defaultValue": true
},
{
"name": "spring.datasource.druid.wall.enabled",
"type": "java.lang.Boolean",
"description": "Whether or not druid wall filter are enabled.",
"description": "Whether or not druid wall-filter are enabled.",
"defaultValue": false
},
{
"name": "spring.datasource.druid.config.enabled",
"type": "java.lang.Boolean",
"description": "Whether or not druid config filter are enabled.",
"description": "Whether or not druid config-filter are enabled.",
"defaultValue": false
},
{
"name": "spring.datasource.druid.slf4j.enabled",
"type": "java.lang.Boolean",
"description": "Whether or not druid slf4j filter are enabled.",
"description": "Whether or not druid slf4j-filter are enabled.",
"defaultValue": false
},
{
"name": "spring.datasource.druid.log4j.enabled",
"type": "java.lang.Boolean",
"description": "Whether or not druid log4j filter are enabled.",
"description": "Whether or not druid log4j-filter are enabled.",
"defaultValue": false
},
{
"name": "spring.datasource.druid.log4j2.enabled",
"type": "java.lang.Boolean",
"description": "Whether or not druid log4j2 filter are enabled.",
"description": "Whether or not druid log4j2-filter are enabled.",
"defaultValue": false
},
{
"name": "spring.datasource.druid.commons-log.enabled",
"type": "java.lang.Boolean",
"description": "Whether or not druid commons logging filter are enabled.",
"description": "Whether or not druid commons-log-filter are enabled.",
"defaultValue": false
},
{
"name": "spring.datasource.druid.aop-stat.enabled",
"type": "java.lang.Boolean",
"description": "Whether or not druid aop stat are enabled.",
"sourceType": "com.github.trang.druid.DruidProperties$AopStat",
"description": "Whether or not druid aop-stat are enabled.",
"sourceType": "com.github.trang.druid.properties.DruidStatProperties$DruidAopStatProperties",
"defaultValue": false
},
{
"name": "spring.datasource.druid.web-stat.enabled",
"type": "java.lang.Boolean",
"description": "Whether or not druid web stat are enabled.",
"sourceType": "com.github.trang.druid.DruidProperties$WebStat",
"description": "Whether or not druid web-stat are enabled.",
"sourceType": "com.github.trang.druid.properties.DruidStatProperties$DruidWebStatProperties",
"defaultValue": false
},
{
"name": "spring.datasource.druid.stat-view-servlet.enabled",
"type": "java.lang.Boolean",
"description": "Whether or not druid stat view servlet are enabled.",
"sourceType": "com.github.trang.druid.DruidProperties$StatViewServlet",
"description": "Whether or not druid stat-view-servlet are enabled.",
"sourceType": "com.github.trang.druid.properties.DruidServletProperties$DruidStatViewServletProperties",
"defaultValue": false
}
],
@@ -1 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.github.trang.druid.DruidAutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.github.trang.druid.DruidAutoConfiguration
+16
View File
@@ -39,6 +39,16 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
@@ -47,6 +57,12 @@
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.drtrang</groupId>
@@ -1,6 +1,7 @@
package com.github.trang.druid;
import com.github.trang.druid.mapper.CityMapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
@@ -12,6 +13,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
* @author trang
*/
@SpringBootApplication
@MapperScan("com.github.trang.druid.mapper")
public class DruidSpringBootStarterApplication implements CommandLineRunner {
public static void main(String[] args) {
@@ -24,7 +26,7 @@ public class DruidSpringBootStarterApplication implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println(cityMapper.findByState("CA"));
System.out.println(cityMapper.findAll());
}
}
@@ -0,0 +1,42 @@
package com.github.trang.druid.config;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 动态数据源,基于简单的轮询算法
*
* @author trang
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
private AtomicInteger count = new AtomicInteger();
private DataSource defaultTargetDataSource;
private Map<String, DataSource> targetDataSources;
public DynamicDataSource(DataSource defaultTargetDataSource, Map<String, DataSource> targetDataSources) {
this.defaultTargetDataSource = defaultTargetDataSource;
this.targetDataSources = targetDataSources;
}
@Override
protected Object determineCurrentLookupKey() {
int i = count.incrementAndGet();
List<String> list = new ArrayList<>(targetDataSources.keySet());
return list.get(i % list.size());
}
@Override
public void afterPropertiesSet() {
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(new HashMap<>(targetDataSources));
super.afterPropertiesSet();
}
}
@@ -0,0 +1,51 @@
package com.github.trang.druid.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.github.trang.druid.datasource.DruidMultiDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
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.Map;
/**
* 多数据源配置,只在 #{@code spring.profiles.active=dynamic} 时生效
*
* @author trang
*/
@Configuration
@Profile("dynamic")
public class SpringDataSourceConfig {
private static final Logger log = LoggerFactory.getLogger(SpringDataSourceConfig.class);
@Bean
@ConfigurationProperties("spring.datasource.druid.one")
public DruidDataSource firstDataSource() {
log.debug("druid master-data-source init...");
return new DruidMultiDataSource();
}
@Bean
@ConfigurationProperties("spring.datasource.druid.two")
public DruidDataSource secondDataSource() {
log.debug("druid slave-data-source init...");
return new DruidMultiDataSource();
}
@Bean
@Primary
public DynamicDataSource dataSource(DruidDataSource firstDataSource, DruidDataSource secondDataSource) {
Map<String, DataSource> targetDataSources = new HashMap<>();
targetDataSources.put("one", firstDataSource);
targetDataSources.put("two", secondDataSource);
return new DynamicDataSource(firstDataSource, targetDataSources);
}
}
@@ -5,11 +5,13 @@ import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface CityMapper {
@Select("select * from city where state = #{state}")
City findByState(@Param("state") String state);
@Select("select * from city")
List<City> findAll();
@Select("select * from city where id = #{id}")
City findById(@Param("id") Long id);
@@ -9,11 +9,14 @@ logging:
com.github.trang: debug
spring:
profiles:
active: single
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:file:./samples
username: root
password: 123456
schema: classpath:/import.sql
druid:
initial-size: 1
min-idle: 1
@@ -55,10 +58,9 @@ spring:
patterns:
- com.github.trang.*
web-stat:
enabled: true
enabled: false
stat-view-servlet:
enabled: true
schema: classpath:import.sql
transaction:
rollback-on-commit-failure: true
aop:
@@ -66,4 +68,31 @@ spring:
proxy-target-class: true
mybatis:
type-aliases-package: com.github.trang.druid.model
type-aliases-package: com.github.trang.druid.model
---
debug: true
spring:
profiles: single
---
debug: true
spring:
profiles: dynamic
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
datasource:
druid:
one:
name: one
max-active: 50
max-open-prepared-statements: 50
two:
name: two
max-active: 25
max-open-prepared-statements: 25
@@ -1,10 +1,14 @@
DROP TABLE IF EXISTS city;
CREATE TABLE city (
id INT(6) PRIMARY KEY AUTO_INCREMENT,
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(64),
state VARCHAR(32),
country VARCHAR(32)
state VARCHAR(16),
country VARCHAR(16)
);
INSERT INTO city (NAME, state, country) VALUES ('Beijing', 'BJ', 'CN');
INSERT INTO city (NAME, state, country) VALUES ('Shanghai', 'SH', 'CN');
INSERT INTO city (NAME, state, country) VALUES ('Guangzhou', 'GZ', 'CN');
INSERT INTO city (NAME, state, country) VALUES ('Shenzhen', 'SZ', 'CN');
INSERT INTO city (NAME, state, country) VALUES ('San Francisco', 'CA', 'US');
@@ -0,0 +1,21 @@
package com.github.trang.druid.test;
import com.github.trang.druid.mapper.CityMapper;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* BaseTest
*
* @author trang
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public abstract class BaseTest {
@Autowired(required = false)
protected CityMapper cityMapper;
}
@@ -0,0 +1,58 @@
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")
public class DynamicDataSourceTests extends BaseTest {
@Autowired
private DruidDataSource firstDataSource;
@Autowired
private DruidDataSource secondDataSource;
@Autowired
private DynamicDataSource dataSource;
@Test
public void testFirstDataSource() {
assertEquals(1, firstDataSource.getInitialSize());
assertEquals(1, firstDataSource.getMinIdle());
assertEquals(50, firstDataSource.getMaxActive());
assertEquals(30000, firstDataSource.getMaxWait());
assertEquals(60000, firstDataSource.getTimeBetweenEvictionRunsMillis());
assertEquals(300000, firstDataSource.getMinEvictableIdleTimeMillis());
assertEquals("SELECT 1", firstDataSource.getValidationQuery());
assertEquals(true, firstDataSource.isTestWhileIdle());
assertEquals(false, firstDataSource.isTestOnBorrow());
assertEquals(false, firstDataSource.isTestOnReturn());
assertEquals(50, firstDataSource.getMaxPoolPreparedStatementPerConnectionSize());
assertEquals(true, firstDataSource.isUseGlobalDataSourceStat());
}
@Test
public void testSecondDataSource() {
assertEquals(1, secondDataSource.getInitialSize());
assertEquals(1, secondDataSource.getMinIdle());
assertEquals(25, secondDataSource.getMaxActive());
assertEquals(30000, secondDataSource.getMaxWait());
assertEquals(60000, secondDataSource.getTimeBetweenEvictionRunsMillis());
assertEquals(300000, secondDataSource.getMinEvictableIdleTimeMillis());
assertEquals("SELECT 1", secondDataSource.getValidationQuery());
assertEquals(true, secondDataSource.isTestWhileIdle());
assertEquals(false, secondDataSource.isTestOnBorrow());
assertEquals(false, secondDataSource.isTestOnReturn());
assertEquals(25, secondDataSource.getMaxPoolPreparedStatementPerConnectionSize());
assertEquals(true, secondDataSource.isUseGlobalDataSourceStat());
}
}
@@ -0,0 +1,29 @@
package com.github.trang.druid.test;
import com.github.trang.druid.model.City;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
/**
* MyBatis 测试
*
* @author trang
*/
public class MyBatisTests extends BaseTest {
@Test
public void testOne() {
City city = cityMapper.findById(1L);
System.out.println(city);
}
@Test
public void testAll() {
List<City> cities = cityMapper.findAll();
System.out.println(cities);
Assert.assertEquals(5, cities.size());
}
}
@@ -1,33 +1,25 @@
package com.github.trang.druid.test;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.wall.WallFilter;
import com.github.trang.druid.mapper.CityMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.ActiveProfiles;
import static org.junit.Assert.assertEquals;
/**
* 单数据源测试
*
* @author trang
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
public class DruidTests {
@ActiveProfiles("single")
public class SingleDataSourceTests extends BaseTest {
@Autowired
private DruidDataSource dataSource;
@Autowired
private WallFilter wallFilter;
@Autowired
private CityMapper cityMapper;
@Test
public void testDataSource() {
public void testSingleDataSource() {
assertEquals(dataSource.getInitialSize(), 1);
assertEquals(dataSource.getMinIdle(), 1);
assertEquals(dataSource.getMaxActive(), 10);
@@ -42,9 +34,4 @@ public class DruidTests {
assertEquals(dataSource.isUseGlobalDataSourceStat(), true);
}
@Test
public void testMybatis() {
System.out.println(cityMapper.findById(1L));
}
}
@@ -1 +1 @@
provides: spring-boot-autoconfigure,druid,druid-spring-boot-autoconfigure
provides: spring-boot-autoconfigure,spring-jdbc,druid,druid-spring-boot-autoconfigure
+23 -1
View File
@@ -45,10 +45,11 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!-- 基础依赖 -->
<spring.version>4.3.9.RELEASE</spring.version>
<spring-boot.version>1.5.4.RELEASE</spring-boot.version>
<slf4j.version>1.7.25</slf4j.version>
<servlet-api.version>3.1.0</servlet-api.version>
<druid.version>1.1.0</druid.version>
<druid.version>1.1.1</druid.version>
<!-- Maven 插件 -->
<maven-dependency-plugin.version>3.0.1</maven-dependency-plugin.version>
<maven-clean-plugin.version>3.0.0</maven-clean-plugin.version>
@@ -79,6 +80,11 @@
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
@@ -126,6 +132,7 @@
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<inherited>true</inherited>
<configuration>
<skip>true</skip>
</configuration>
@@ -141,11 +148,13 @@
<groupId>org.eluder.coveralls</groupId>
<artifactId>coveralls-maven-plugin</artifactId>
<version>${coveralls-maven-plugin.version}</version>
<inherited>true</inherited>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${cobertura-maven-plugin.version}</version>
<inherited>true</inherited>
<configuration>
<format>xml</format>
<maxmem>256m</maxmem>
@@ -165,6 +174,7 @@
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven-javadoc-plugin.version}</version>
<inherited>true</inherited>
<executions>
<execution>
<phase>package</phase>
@@ -181,6 +191,7 @@
<plugin>
<artifactId>maven-gpg-plugin</artifactId>
<version>${maven-gpg-plugin.version}</version>
<inherited>true</inherited>
<executions>
<execution>
<phase>verify</phase>
@@ -193,6 +204,7 @@
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
<inherited>true</inherited>
<configuration>
<updateReleaseInfo>true</updateReleaseInfo>
</configuration>
@@ -200,6 +212,7 @@
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>${maven-release-plugin.version}</version>
<inherited>true</inherited>
<configuration>
<autoVersionSubmodules>true</autoVersionSubmodules>
<useReleaseProfile>true</useReleaseProfile>
@@ -219,10 +232,12 @@
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>${maven-dependency-plugin.version}</version>
<inherited>true</inherited>
</plugin>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<version>${maven-enforcer-plugin.version}</version>
<inherited>true</inherited>
<executions>
<execution>
<id>enforce-maven</id>
@@ -242,10 +257,12 @@
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>${maven-clean-plugin.version}</version>
<inherited>true</inherited>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>${maven-resources-plugin.version}</version>
<inherited>true</inherited>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
@@ -253,6 +270,7 @@
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<inherited>true</inherited>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
<source>${java.version}</source>
@@ -262,6 +280,7 @@
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<inherited>true</inherited>
<configuration>
<includes>
<include>**/com/github/trang/**/test/junit/**Test.java</include>
@@ -271,10 +290,12 @@
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<inherited>true</inherited>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>${maven-source-plugin.version}</version>
<inherited>true</inherited>
<executions>
<execution>
<phase>package</phase>
@@ -287,6 +308,7 @@
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>${maven-install-plugin.version}</version>
<inherited>true</inherited>
</plugin>
</plugins>
</build>