diff --git a/druid-spring-boot-starter/src/main/java/com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceAutoConfigure.java b/druid-spring-boot-starter/src/main/java/com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceAutoConfigure.java index 558e1f24b9..16322d86ff 100644 --- a/druid-spring-boot-starter/src/main/java/com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceAutoConfigure.java +++ b/druid-spring-boot-starter/src/main/java/com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceAutoConfigure.java @@ -18,7 +18,6 @@ package com.alibaba.druid.spring.boot.autoconfigure; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -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; @@ -33,15 +32,16 @@ import java.sql.SQLException; */ @Configuration @ConditionalOnClass(com.alibaba.druid.pool.DruidDataSource.class) -@EnableConfigurationProperties(DruidStatProperties.class) +@EnableConfigurationProperties({DruidStatProperties.class, DruidDataSourceProperties.class}) @Import({DruidSpringAopConfiguration.class, DruidStatViewServletConfiguration.class, DruidWebStatFilterConfiguration.class}) public class DruidDataSourceAutoConfigure { @Bean - @ConfigurationProperties("spring.datasource.druid") @ConditionalOnMissingBean - public DataSource dataSource(Environment env) { - DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); + public DataSource dataSource(DruidDataSourceProperties properties, Environment env) { + DruidDataSource dataSource = DruidDataSourceBuilder + .create() + .build(properties); //if not found prefix 'spring.datasource.druid' settings,'spring.datasource' prefix settings will be used. if (dataSource.getUsername() == null) { diff --git a/druid-spring-boot-starter/src/main/java/com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceBuilder.java b/druid-spring-boot-starter/src/main/java/com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceBuilder.java index 6f13dba29e..bb38858958 100644 --- a/druid-spring-boot-starter/src/main/java/com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceBuilder.java +++ b/druid-spring-boot-starter/src/main/java/com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceBuilder.java @@ -17,46 +17,129 @@ package com.alibaba.druid.spring.boot.autoconfigure; import com.alibaba.druid.pool.DruidDataSource; -import org.springframework.beans.MutablePropertyValues; -import org.springframework.boot.bind.RelaxedDataBinder; -import org.springframework.boot.jdbc.DatabaseDriver; +import org.springframework.core.env.Environment; -import java.util.HashMap; -import java.util.Map; +import java.sql.SQLException; /** * @author lihengming [89921218@qq.com] */ public class DruidDataSourceBuilder { - private Map properties = new HashMap(); - public static DruidDataSourceBuilder create() { return new DruidDataSourceBuilder(); } + @Deprecated public DruidDataSource build() { + return new DruidDataSource(); + } + + /** + * Use Spring Environment by specify configuration properties prefix to build DruidDataSource. + *

+ * Environment support .properties, .yml ,command etc. + *

+ * Properties key style support max-active,MAX_ACTIVE,maxActive etc. + *

+ * Please read the spring documents for details. + * @param env Spring Environment + * @param prefix Spring Boot configuration properties prefix + * @return DruidDataSource + */ + public DruidDataSource build(Environment env, String prefix) { + DruidDataSourceProperties properties = new DruidDataSourceProperties(); + properties.setUrl(env.getProperty(prefix + "url")); + properties.setUsername(env.getProperty(prefix + "username")); + properties.setPassword(env.getProperty(prefix + "password")); + properties.setDriverClassName(env.getProperty(prefix + "driver-class-name")); + properties.setInitialSize(env.getProperty(prefix + "initial-size", Integer.class)); + properties.setMaxActive(env.getProperty(prefix + "max-active", Integer.class)); + properties.setMinIdle(env.getProperty(prefix + "min-idle", Integer.class)); + properties.setMaxWait(env.getProperty(prefix + "max-wait", Long.class)); + properties.setPoolPreparedStatements(env.getProperty(prefix + "pool-prepared-statements", Boolean.class)); + properties.setMaxOpenPreparedStatements(env.getProperty(prefix + "max-open-prepared-statements", Integer.class)); + properties.setMaxPoolPreparedStatementPerConnectionSize( + env.getProperty(prefix + "max-pool-prepared-statement-per-connection-size", Integer.class)); + properties.setValidationQuery(env.getProperty(prefix + "validation-query")); + properties.setValidationQueryTimeout(env.getProperty(prefix + "validation-query-timeout", Integer.class)); + properties.setTestOnBorrow(env.getProperty(prefix + "test-on-borrow", Boolean.class)); + properties.setTestOnReturn(env.getProperty(prefix + "test-on-return", Boolean.class)); + properties.setTestWhileIdle(env.getProperty(prefix + "test-while-idle", Boolean.class)); + properties.setTimeBetweenEvictionRunsMillis(env.getProperty(prefix + "time-between-eviction-runs-millis", Long.class)); + properties.setMinEvictableIdleTimeMillis(env.getProperty(prefix + "min-evictable-idle-time-millis", Long.class)); + properties.setMaxEvictableIdleTimeMillis(env.getProperty(prefix + "max-evictable-idle-time-millis", Long.class)); + properties.setFilters(env.getProperty(prefix + "filters")); + return build(properties); + } + + + DruidDataSource build(DruidDataSourceProperties properties) { DruidDataSource dataSource = new DruidDataSource(); - maybeGetDriverClassName(); - bind(dataSource); + if (properties.getUrl() != null) { + dataSource.setUrl(properties.getUrl()); + } + if (properties.getUsername() != null) { + dataSource.setUsername(properties.getUsername()); + } + if (properties.getPassword() != null) { + dataSource.setPassword(properties.getPassword()); + } + if (properties.getDriverClassName() != null) { + dataSource.setDriverClassName(properties.getDriverClassName()); + } + if (properties.getInitialSize() != null) { + dataSource.setInitialSize(properties.getInitialSize()); + } + if (properties.getMaxActive() != null) { + dataSource.setMaxActive(properties.getMaxActive()); + } + if (properties.getMinIdle() != null) { + dataSource.setMinIdle(properties.getMinIdle()); + } + if (properties.getMaxWait() != null) { + dataSource.setMaxWait(properties.getMaxWait()); + } + if (properties.getPoolPreparedStatements() != null) { + dataSource.setPoolPreparedStatements(properties.getPoolPreparedStatements()); + } + if (properties.getMaxOpenPreparedStatements() != null) { + dataSource.setMaxOpenPreparedStatements(properties.getMaxOpenPreparedStatements()); + } + if (properties.getMaxPoolPreparedStatementPerConnectionSize() != null) { + dataSource.setMaxPoolPreparedStatementPerConnectionSize(properties.getMaxPoolPreparedStatementPerConnectionSize()); + } + if (properties.getValidationQuery() != null) { + dataSource.setValidationQuery(properties.getValidationQuery()); + } + if (properties.getValidationQueryTimeout() != null) { + dataSource.setValidationQueryTimeout(properties.getValidationQueryTimeout()); + } + if (properties.getTestWhileIdle() != null) { + dataSource.setTestWhileIdle(properties.getTestWhileIdle()); + } + if (properties.getTestOnBorrow() != null) { + dataSource.setTestOnBorrow(properties.getTestOnBorrow()); + } + if (properties.getTestOnReturn() != null) { + dataSource.setTestOnReturn(properties.getTestOnReturn()); + } + if (properties.getTimeBetweenEvictionRunsMillis() != null) { + dataSource.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRunsMillis()); + } + if (properties.getMinEvictableIdleTimeMillis() != null) { + dataSource.setMinEvictableIdleTimeMillis(properties.getMinEvictableIdleTimeMillis()); + } + if (properties.getMaxEvictableIdleTimeMillis() != null) { + dataSource.setMaxEvictableIdleTimeMillis(properties.getMaxEvictableIdleTimeMillis()); + } + try { + if (properties.getFilters() != null) { + dataSource.setFilters(properties.getFilters()); + } + } catch (SQLException e) { + e.printStackTrace(); + } return dataSource; } - - //use spring boot relaxed binding by reflection config druid . detail see Spring Boot Reference Relaxed binding section. - private void bind(DruidDataSource result) { - MutablePropertyValues properties = new MutablePropertyValues(this.properties); - new RelaxedDataBinder(result) - .withAlias("url", "jdbcUrl") - .withAlias("username", "user") - .bind(properties); - } - - private void maybeGetDriverClassName() { - if (!this.properties.containsKey("driverClassName") - && this.properties.containsKey("url")) { - String url = this.properties.get("url"); - String driverClass = DatabaseDriver.fromJdbcUrl(url).getDriverClassName(); - this.properties.put("driverClassName", driverClass); - } - } } diff --git a/druid-spring-boot-starter/src/main/java/com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceProperties.java b/druid-spring-boot-starter/src/main/java/com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceProperties.java new file mode 100644 index 0000000000..60ee25feea --- /dev/null +++ b/druid-spring-boot-starter/src/main/java/com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceProperties.java @@ -0,0 +1,219 @@ +package com.alibaba.druid.spring.boot.autoconfigure; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author lihengming [89921218@qq.com] + */ +@ConfigurationProperties("spring.datasource.druid") +public class DruidDataSourceProperties { + private String url; + + private String username; + + private String password; + + private String driverClassName; + + private Integer initialSize; + + private Integer maxActive; + + private Integer minIdle; + + private Long maxWait; + + private Boolean poolPreparedStatements; + + private Integer maxOpenPreparedStatements; + + private Integer maxPoolPreparedStatementPerConnectionSize; + + private String validationQuery; + + private Integer validationQueryTimeout; + + private Boolean testOnBorrow; + + private Boolean testOnReturn; + + private Boolean testWhileIdle; + + private Long timeBetweenEvictionRunsMillis; + + private Long minEvictableIdleTimeMillis; + + private Long maxEvictableIdleTimeMillis; + + private String filters; + + private String proxyFilters; + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getDriverClassName() { + return driverClassName; + } + + public void setDriverClassName(String driverClassName) { + this.driverClassName = driverClassName; + } + + public Integer getInitialSize() { + return initialSize; + } + + public void setInitialSize(Integer initialSize) { + this.initialSize = initialSize; + } + + public Integer getMaxActive() { + return maxActive; + } + + public void setMaxActive(Integer maxActive) { + this.maxActive = maxActive; + } + + public Integer getMinIdle() { + return minIdle; + } + + public void setMinIdle(Integer minIdle) { + this.minIdle = minIdle; + } + + public Long getMaxWait() { + return maxWait; + } + + public void setMaxWait(Long maxWait) { + this.maxWait = maxWait; + } + + public Boolean getPoolPreparedStatements() { + return poolPreparedStatements; + } + + public void setPoolPreparedStatements(Boolean poolPreparedStatements) { + this.poolPreparedStatements = poolPreparedStatements; + } + + public Integer getMaxOpenPreparedStatements() { + return maxOpenPreparedStatements; + } + + public void setMaxOpenPreparedStatements(Integer maxOpenPreparedStatements) { + this.maxOpenPreparedStatements = maxOpenPreparedStatements; + } + + public Integer getMaxPoolPreparedStatementPerConnectionSize() { + return maxPoolPreparedStatementPerConnectionSize; + } + + public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) { + this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize; + } + + public String getValidationQuery() { + return validationQuery; + } + + public void setValidationQuery(String validationQuery) { + this.validationQuery = validationQuery; + } + + public Integer getValidationQueryTimeout() { + return validationQueryTimeout; + } + + public void setValidationQueryTimeout(Integer validationQueryTimeout) { + this.validationQueryTimeout = validationQueryTimeout; + } + + public Boolean getTestOnBorrow() { + return testOnBorrow; + } + + public void setTestOnBorrow(Boolean testOnBorrow) { + this.testOnBorrow = testOnBorrow; + } + + public Boolean getTestOnReturn() { + return testOnReturn; + } + + public void setTestOnReturn(Boolean testOnReturn) { + this.testOnReturn = testOnReturn; + } + + public Boolean getTestWhileIdle() { + return testWhileIdle; + } + + public void setTestWhileIdle(Boolean testWhileIdle) { + this.testWhileIdle = testWhileIdle; + } + + public Long getTimeBetweenEvictionRunsMillis() { + return timeBetweenEvictionRunsMillis; + } + + public void setTimeBetweenEvictionRunsMillis(Long timeBetweenEvictionRunsMillis) { + this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; + } + + public Long getMinEvictableIdleTimeMillis() { + return minEvictableIdleTimeMillis; + } + + public void setMinEvictableIdleTimeMillis(Long minEvictableIdleTimeMillis) { + this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; + } + + public Long getMaxEvictableIdleTimeMillis() { + return maxEvictableIdleTimeMillis; + } + + public void setMaxEvictableIdleTimeMillis(Long maxEvictableIdleTimeMillis) { + this.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis; + } + + public String getFilters() { + return filters; + } + + public void setFilters(String filters) { + this.filters = filters; + } + + public String getProxyFilters() { + return proxyFilters; + } + + public void setProxyFilters(String proxyFilters) { + this.proxyFilters = proxyFilters; + } +} diff --git a/druid-spring-boot-starter/src/test/java/com/alibaba/druid/spring/boot/DruidDataSourceTestCase.java b/druid-spring-boot-starter/src/test/java/com/alibaba/druid/spring/boot/DruidDataSourceTestCase.java index 8ed367e1df..56a179be16 100644 --- a/druid-spring-boot-starter/src/test/java/com/alibaba/druid/spring/boot/DruidDataSourceTestCase.java +++ b/druid-spring-boot-starter/src/test/java/com/alibaba/druid/spring/boot/DruidDataSourceTestCase.java @@ -15,14 +15,12 @@ */ package com.alibaba.druid.spring.boot; import com.alibaba.druid.pool.DruidDataSource; -import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; import org.junit.Test; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import javax.sql.DataSource; @@ -50,47 +48,50 @@ public class DruidDataSourceTestCase { public void testDataSourcePropertiesOverridden() throws Exception { this.context.register(DruidDataSourceConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "url=jdbc:h2:file:./demo-db"); + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "initial-size=2"); + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "max-active=30"); + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "min-idle=2"); + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "max-wait=1234"); + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "pool-prepared-statements=true"); + //EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "max-open-prepared-statements=5");//Duplicated with following + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "max-pool-prepared-statement-per-connection-size=5"); + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "validation-query=select 'x'"); + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "validation-query-timeout=1"); + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "test-on-borrow=true"); + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "test-while-idle=true"); + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "test-on-return=true"); + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "time-between-eviction-runs-millis=10000"); + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "min-evictable-idle-time-millis=12345"); + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "max-evictable-idle-time-millis=123456"); EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "filters=stat,log4j"); - EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "maxActive=30"); - EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "initialSize=2"); - EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "maxWait=1234"); - EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "minIdle=2"); - EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "timeBetweenEvictionRunsMillis=10000"); - EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "minEvictableIdleTimeMillis=12345"); - EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "testWhileIdle=true"); - EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "testOnBorrow=true"); - EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "testOnReturn=true"); - EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "poolPreparedStatements=true"); - EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "maxOpenPreparedStatements=15"); this.context.refresh(); DruidDataSource ds = this.context.getBean(DruidDataSource.class); assertThat(ds.getUrl()).isEqualTo("jdbc:h2:file:./demo-db"); - assertThat(ds.getProxyFilters().size()).isEqualTo(2); - assertThat(ds.getMaxActive()).isEqualTo(30); assertThat(ds.getInitialSize()).isEqualTo(2); - assertThat(ds.getMaxWait()).isEqualTo(1234); + assertThat(ds.getMaxActive()).isEqualTo(30); assertThat(ds.getMinIdle()).isEqualTo(2); - assertThat(ds.getTimeBetweenEvictionRunsMillis()).isEqualTo(10000); - assertThat(ds.getMinEvictableIdleTimeMillis()).isEqualTo(12345); + assertThat(ds.getMaxWait()).isEqualTo(1234); + assertThat(ds.isPoolPreparedStatements()).isTrue(); + //assertThat(ds.getMaxOpenPreparedStatements()).isEqualTo(5); //Duplicated with following + assertThat(ds.getMaxPoolPreparedStatementPerConnectionSize()).isEqualTo(5); + assertThat(ds.getValidationQuery()).isEqualTo("select 'x'"); + assertThat(ds.getValidationQueryTimeout()).isEqualTo(1); assertThat(ds.isTestWhileIdle()).isTrue(); assertThat(ds.isTestOnBorrow()).isTrue(); assertThat(ds.isTestOnReturn()).isTrue(); - assertThat(ds.isPoolPreparedStatements()).isTrue(); - assertThat(ds.getMaxOpenPreparedStatements()).isEqualTo(15); + assertThat(ds.getTimeBetweenEvictionRunsMillis()).isEqualTo(10000); + assertThat(ds.getMinEvictableIdleTimeMillis()).isEqualTo(12345); + assertThat(ds.getMaxEvictableIdleTimeMillis()).isEqualTo(123456); + assertThat(ds.getProxyFilters().size()).isEqualTo(2); } @Configuration - @EnableConfigurationProperties + @Import(DruidDataSourceAutoConfigure.class) protected static class DruidDataSourceConfiguration { - @Bean - @ConfigurationProperties(prefix = "spring.datasource.druid") - public DataSource dataSource() { - return DruidDataSourceBuilder.create().build(); - } } }