Integrate @ConfigurationProperties @Beans with DataSource configuration

We now have a much simpler DataSourceAutoConfiguration that binds to whatever
DataSource concrete type it finds at runtime. To be able to quickly switch between
Hikari and the other types of DataSource there's a minute shim for translating
the common properties (username, password, url, driverClassName), but actually
only url is different. The shim and also DataSource initialization is supported
through DataSourceProperties, but the other native properties get bound directly
through the concrete runtime type of the DataSource.

The /configprops endpoint works (and is exposed in the actuator sample).

Fixes gh-840, fixes gh-477, see also gh-808.
pull/874/head
Dave Syer 11 years ago
parent 660b73b5c6
commit 5249f54c5a

@ -34,11 +34,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jdbc.CommonsDataSourceConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
import org.springframework.boot.autoconfigure.jdbc.HikariDataSourceConfiguration;
import org.springframework.boot.autoconfigure.jdbc.TomcatDataSourceConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration;
@ -54,11 +50,9 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
* @since 1.1.0
*/
@Configuration
@AutoConfigureAfter({ DataSourceAutoConfiguration.class,
EmbeddedDataSourceConfiguration.class, CommonsDataSourceConfiguration.class,
HikariDataSourceConfiguration.class, TomcatDataSourceConfiguration.class,
MongoAutoConfiguration.class, MongoDataAutoConfiguration.class,
RedisAutoConfiguration.class, RabbitAutoConfiguration.class })
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MongoAutoConfiguration.class,
MongoDataAutoConfiguration.class, RedisAutoConfiguration.class,
RabbitAutoConfiguration.class })
public class HealthIndicatorAutoConfiguration {
@Bean

@ -0,0 +1,110 @@
/*
* Copyright 2013-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint;
import java.util.Map;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.context.properties.ConfigurationBeanFactoryMetaData;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class ConfigurationPropertiesReportEndpointSerializationTests {
private AnnotationConfigApplicationContext context;
@Before
public void setup() {
this.context = new AnnotationConfigApplicationContext();
}
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
@SuppressWarnings("unchecked")
public void testNaming() throws Exception {
this.context.register(Config.class);
EnvironmentTestUtils.addEnvironment(this.context, "foo.name:foo");
this.context.refresh();
ConfigurationPropertiesReportEndpoint report = this.context
.getBean(ConfigurationPropertiesReportEndpoint.class);
Map<String, Object> properties = report.invoke();
Map<String, Object> nestedProperties = (Map<String, Object>) properties
.get("foo");
assertNotNull(nestedProperties);
assertEquals("foo", nestedProperties.get("prefix"));
Map<String, Object> map = (Map<String, Object>) nestedProperties
.get("properties");
assertNotNull(map);
assertEquals(1, map.size());
assertEquals("foo", map.get("name"));
}
@Configuration
@EnableConfigurationProperties
public static class Config {
@Bean
public ConfigurationPropertiesReportEndpoint endpoint(
ConfigurationBeanFactoryMetaData beanFactoryMetaData) {
ConfigurationPropertiesReportEndpoint endpoint = new ConfigurationPropertiesReportEndpoint();
endpoint.setConfigurationBeanFactoryMetaData(beanFactoryMetaData);
return endpoint;
}
@Bean
@ConfigurationProperties(prefix = "foo")
public Foo foo() {
return new Foo();
}
}
public static class Foo {
private String name = "654321";
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
// No setter so it doesn't appear in the report
public String getSummary() {
return "Name: " + this.name;
}
}
}

@ -1,101 +0,0 @@
/*
* Copyright 2012-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.jdbc;
import java.sql.SQLException;
import javax.annotation.PreDestroy;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.DataAccessResourceFailureException;
/**
* Configuration for a Commons DBCP database pool. The DBCP pool is popular but not
* recommended in high volume environments (the Tomcat DataSource is more reliable).
*
* @author Dave Syer
* @see DataSourceAutoConfiguration
*/
@Configuration
public class CommonsDataSourceConfiguration extends AbstractDataSourceConfiguration {
private static Log logger = LogFactory.getLog(CommonsDataSourceConfiguration.class);
private BasicDataSource pool;
public CommonsDataSourceConfiguration() {
// Ensure to set the correct default value for Commons DBCP
setInitialSize(0);
}
@Bean(destroyMethod = "close")
public DataSource dataSource() {
logger.info("Hint: using Commons DBCP BasicDataSource. It's going to work, "
+ "but the Tomcat DataSource is more reliable.");
this.pool = createAndConfigurePool();
return this.pool;
}
private BasicDataSource createAndConfigurePool() {
BasicDataSource pool = new BasicDataSource();
pool.setDriverClassName(getDriverClassName());
pool.setUrl(getUrl());
if (getUsername() != null) {
pool.setUsername(getUsername());
}
if (getPassword() != null) {
pool.setPassword(getPassword());
}
pool.setInitialSize(getInitialSize());
pool.setMaxActive(getMaxActive());
pool.setMaxIdle(getMaxIdle());
pool.setMinIdle(getMinIdle());
pool.setTestOnBorrow(isTestOnBorrow());
pool.setTestOnReturn(isTestOnReturn());
pool.setTestWhileIdle(isTestWhileIdle());
pool.setValidationQuery(getValidationQuery());
if (getTimeBetweenEvictionRunsMillis() != null) {
pool.setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis());
}
if (getMinEvictableIdleTimeMillis() != null) {
pool.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis());
}
if (getMaxWaitMillis() != null) {
pool.setMaxWait(getMaxWaitMillis());
}
return pool;
}
@PreDestroy
public void close() {
if (this.pool != null) {
try {
this.pool.close();
}
catch (SQLException ex) {
throw new DataAccessResourceFailureException(
"Could not close data source", ex);
}
}
}
}

@ -35,16 +35,15 @@ import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.jdbc.core.JdbcOperations;
@ -54,7 +53,6 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
@ -65,7 +63,8 @@ import org.springframework.util.StringUtils;
*/
@Configuration
@ConditionalOnClass(EmbeddedDatabaseType.class)
public class DataSourceAutoConfiguration implements EnvironmentAware {
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
private static Log logger = LogFactory.getLog(DataSourceAutoConfiguration.class);
@ -77,26 +76,20 @@ public class DataSourceAutoConfiguration implements EnvironmentAware {
@Autowired
private ApplicationContext applicationContext;
private RelaxedPropertyResolver datasourceProperties;
@Override
public void setEnvironment(Environment environment) {
this.datasourceProperties = new RelaxedPropertyResolver(environment,
CONFIGURATION_PREFIX + ".");
}
@Autowired
private DataSourceProperties properties;
@PostConstruct
protected void initialize() throws Exception {
boolean initialize = this.datasourceProperties.getProperty("initialize",
Boolean.class, true);
boolean initialize = this.properties.isInitialize();
if (this.dataSource == null || !initialize) {
logger.debug("No DataSource found so not initializing");
return;
}
String schema = this.datasourceProperties.getProperty("schema");
String schema = this.properties.getSchema();
if (schema == null) {
String platform = this.datasourceProperties.getProperty("platform", "all");
String platform = this.properties.getPlatform();
schema = "classpath*:schema-" + platform + ".sql,";
schema += "classpath*:schema.sql,";
schema += "classpath*:data-" + platform + ".sql,";
@ -109,8 +102,7 @@ public class DataSourceAutoConfiguration implements EnvironmentAware {
.getResources(schemaLocation)));
}
boolean continueOnError = this.datasourceProperties.getProperty(
"continueOnError", Boolean.class, false);
boolean continueOnError = this.properties.isContinueOnError();
boolean exists = false;
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
for (Resource resource : resources) {
@ -120,7 +112,7 @@ public class DataSourceAutoConfiguration implements EnvironmentAware {
populator.setContinueOnError(continueOnError);
}
}
populator.setSeparator(this.datasourceProperties.getProperty("separator", ";"));
populator.setSeparator(this.properties.getSeparator());
if (exists) {
DatabasePopulatorUtils.execute(populator, this.dataSource);
@ -151,24 +143,26 @@ public class DataSourceAutoConfiguration implements EnvironmentAware {
}
@Conditional(DataSourceAutoConfiguration.TomcatDatabaseCondition.class)
@Conditional(DataSourceAutoConfiguration.NonEmbeddedDatabaseCondition.class)
@ConditionalOnMissingBean(DataSource.class)
@Import(TomcatDataSourceConfiguration.class)
protected static class TomcatConfiguration {
protected static class NonEmbeddedConfiguration {
}
@Autowired
private DataSourceProperties properties;
@Conditional(DataSourceAutoConfiguration.HikariDatabaseCondition.class)
@ConditionalOnMissingBean(DataSource.class)
@Import(HikariDataSourceConfiguration.class)
protected static class HikariConfiguration {
}
@Conditional(DataSourceAutoConfiguration.BasicDatabaseCondition.class)
@ConditionalOnMissingBean(DataSource.class)
@Import(CommonsDataSourceConfiguration.class)
protected static class DbcpConfiguration {
@ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX)
@Bean
public DataSource dataSource() {
// @formatter:off
DataSourceFactory factory = DataSourceFactory
.create(this.properties.getClassLoader())
.driverClassName(this.properties.getDriverClassName())
.url(this.properties.getUrl())
.username(this.properties.getUsername())
.password(this.properties.getPassword());
// @formatter:on
return factory.build();
}
}
@ -196,35 +190,18 @@ public class DataSourceAutoConfiguration implements EnvironmentAware {
/**
* Base {@link Condition} for non-embedded database checks.
*/
static abstract class NonEmbeddedDatabaseCondition extends SpringBootCondition {
protected abstract String getDataSourceClassName();
static class NonEmbeddedDatabaseCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
if (!ClassUtils.isPresent(getDataSourceClassName(), context.getClassLoader())) {
return ConditionOutcome.noMatch(getDataSourceClassName()
+ " DataSource class not found");
}
String driverClassName = getDriverClassName(context.getEnvironment(),
getDataSourceClassLoader(context));
if (driverClassName == null) {
return ConditionOutcome.noMatch("no database driver");
}
String url = getUrl(context.getEnvironment(), context.getClassLoader());
if (url == null) {
return ConditionOutcome.noMatch("no database URL");
}
if (ClassUtils.isPresent(driverClassName, context.getClassLoader())) {
return ConditionOutcome.match("found database driver " + driverClassName);
ClassLoader dataSourceClassLoader = getDataSourceClassLoader(context);
if (dataSourceClassLoader != null) {
return ConditionOutcome.match("Supported DataSource class found");
}
return ConditionOutcome.noMatch("missing database driver " + driverClassName);
return ConditionOutcome.noMatch("missing supported DataSource");
}
/**
@ -232,94 +209,12 @@ public class DataSourceAutoConfiguration implements EnvironmentAware {
* the driver class can actually be loaded by the data source.
*/
private ClassLoader getDataSourceClassLoader(ConditionContext context) {
try {
Class<?> dataSourceClass = ClassUtils.forName(getDataSourceClassName(),
context.getClassLoader());
return dataSourceClass.getClassLoader();
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(ex);
}
}
private String getDriverClassName(Environment environment, ClassLoader classLoader) {
String driverClassName = environment == null ? null : environment
.getProperty(CONFIGURATION_PREFIX + ".driverClassName");
if (driverClassName == null) {
driverClassName = EmbeddedDatabaseConnection.get(classLoader)
.getDriverClassName();
}
return driverClassName;
}
private String getUrl(Environment environment, ClassLoader classLoader) {
String url = (environment == null ? null : environment
.getProperty(CONFIGURATION_PREFIX + ".url"));
if (url == null) {
url = EmbeddedDatabaseConnection.get(classLoader).getUrl();
}
return url;
}
}
/**
* {@link Condition} to detect when a commons-dbcp {@code BasicDataSource} backed
* database is used.
*/
static class BasicDatabaseCondition extends NonEmbeddedDatabaseCondition {
private final Condition hikariCondition = new HikariDatabaseCondition();
private final Condition tomcatCondition = new TomcatDatabaseCondition();
@Override
protected String getDataSourceClassName() {
return "org.apache.commons.dbcp.BasicDataSource";
}
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
if (anyMatches(context, metadata, this.hikariCondition, this.tomcatCondition)) {
return ConditionOutcome.noMatch("other DataSource");
}
return super.getMatchOutcome(context, metadata);
}
}
/**
* {@link Condition} to detect when a Hikari DataSource backed database is used.
*/
static class HikariDatabaseCondition extends NonEmbeddedDatabaseCondition {
private final Condition tomcatCondition = new TomcatDatabaseCondition();
@Override
protected String getDataSourceClassName() {
return "com.zaxxer.hikari.HikariDataSource";
}
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
if (anyMatches(context, metadata, this.tomcatCondition)) {
return ConditionOutcome.noMatch("Tomcat DataSource");
Class<?> dataSourceClass = new DataSourceFactory(context.getClassLoader())
.findType();
if (dataSourceClass == null) {
return null;
}
return super.getMatchOutcome(context, metadata);
}
}
/**
* {@link Condition} to detect when a Tomcat DataSource backed database is used.
*/
static class TomcatDatabaseCondition extends NonEmbeddedDatabaseCondition {
@Override
protected String getDataSourceClassName() {
return "org.apache.tomcat.jdbc.pool.DataSource";
return dataSourceClass.getClassLoader();
}
}
@ -329,17 +224,12 @@ public class DataSourceAutoConfiguration implements EnvironmentAware {
*/
static class EmbeddedDatabaseCondition extends SpringBootCondition {
private final SpringBootCondition hikariCondition = new HikariDatabaseCondition();
private final SpringBootCondition tomcatCondition = new TomcatDatabaseCondition();
private final SpringBootCondition dbcpCondition = new BasicDatabaseCondition();
private final SpringBootCondition nonEmbedded = new NonEmbeddedDatabaseCondition();
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
if (anyMatches(context, metadata, this.hikariCondition, this.tomcatCondition,
this.dbcpCondition)) {
if (anyMatches(context, metadata, this.nonEmbedded)) {
return ConditionOutcome
.noMatch("existing non-embedded database detected");
}
@ -358,11 +248,7 @@ public class DataSourceAutoConfiguration implements EnvironmentAware {
*/
static class DatabaseCondition extends SpringBootCondition {
private final SpringBootCondition hikariCondition = new HikariDatabaseCondition();
private final SpringBootCondition tomcatCondition = new TomcatDatabaseCondition();
private final SpringBootCondition dbcpCondition = new BasicDatabaseCondition();
private final SpringBootCondition nonEmbedded = new NonEmbeddedDatabaseCondition();
private final SpringBootCondition embeddedCondition = new EmbeddedDatabaseCondition();
@ -370,8 +256,7 @@ public class DataSourceAutoConfiguration implements EnvironmentAware {
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
if (anyMatches(context, metadata, this.hikariCondition, this.tomcatCondition,
this.dbcpCondition, this.embeddedCondition)) {
if (anyMatches(context, metadata, this.nonEmbedded, this.embeddedCondition)) {
return ConditionOutcome.match("existing auto database detected");
}

@ -0,0 +1,133 @@
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.jdbc;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.util.ClassUtils;
/**
* Convenience class for building a {@link DataSource} with common implementations and
* properties. If Tomcat, HikariCP or Commons DBCP are on the classpath one of them will
* be selected (in that order with Tomcat first). In the interest of a uniform interface,
* and so that there can be a fallback to an embedded database if one can be detected on
* the classpath, only a small set of common configuration properties are supported. To
* inject additional properties into the result you can downcast it, or use
* <code>@ConfigurationProperties</code>.
*
* @author Dave Syer
*/
public class DataSourceFactory {
private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {
"org.apache.tomcat.jdbc.pool.DataSource",
"com.zaxxer.hikari.HikariDataSource",
"org.apache.commons.dbcp.BasicDataSource" };
private Class<? extends DataSource> type;
private ClassLoader classLoader;
private Map<String, String> properties = new HashMap<String, String>();
public static DataSourceFactory create() {
return new DataSourceFactory(null);
}
public static DataSourceFactory create(ClassLoader classLoader) {
return new DataSourceFactory(classLoader);
}
public DataSourceFactory(ClassLoader classLoader) {
this.classLoader = classLoader;
}
public DataSource build() {
Class<? extends DataSource> type = getType();
DataSource result = BeanUtils.instantiate(type);
bind(result);
return result;
}
private void bind(DataSource result) {
new RelaxedDataBinder(result).bind(getPropertyValues());
}
private PropertyValues getPropertyValues() {
if (getType().getName().contains("Hikari") && this.properties.containsKey("url")) {
this.properties.put("jdbcUrl", this.properties.get("url"));
this.properties.remove("url");
}
return new MutablePropertyValues(this.properties);
}
public DataSourceFactory type(Class<? extends DataSource> type) {
this.type = type;
return this;
}
public DataSourceFactory url(String url) {
this.properties.put("url", url);
return this;
}
public DataSourceFactory driverClassName(String driverClassName) {
this.properties.put("driverClassName", driverClassName);
return this;
}
public DataSourceFactory username(String username) {
this.properties.put("username", username);
return this;
}
public DataSourceFactory password(String password) {
this.properties.put("password", password);
return this;
}
public Class<? extends DataSource> findType() {
if (this.type != null) {
return this.type;
}
for (String name : DATA_SOURCE_TYPE_NAMES) {
if (ClassUtils.isPresent(name, this.classLoader)) {
@SuppressWarnings("unchecked")
Class<DataSource> resolved = (Class<DataSource>) ClassUtils
.resolveClassName(name, this.classLoader);
return resolved;
}
}
return null;
}
private Class<? extends DataSource> getType() {
Class<? extends DataSource> type = findType();
if (type != null) {
return type;
}
throw new IllegalStateException("No supported DataSource type found");
}
}

@ -20,7 +20,6 @@ import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.util.StringUtils;
/**
@ -29,9 +28,7 @@ import org.springframework.util.StringUtils;
* @author Dave Syer
*/
@ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX)
@EnableConfigurationProperties
public abstract class AbstractDataSourceConfiguration implements BeanClassLoaderAware,
InitializingBean {
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
private String driverClassName;
@ -41,29 +38,17 @@ public abstract class AbstractDataSourceConfiguration implements BeanClassLoader
private String password;
private int maxActive = 100;
private int maxIdle = 8;
private int minIdle = 8;
private int initialSize = 10;
private String validationQuery;
private boolean testOnBorrow;
private boolean testOnReturn;
private ClassLoader classLoader;
private boolean testWhileIdle;
private boolean initialize = true;
private Integer timeBetweenEvictionRunsMillis;
private String platform = "all";
private Integer minEvictableIdleTimeMillis;
private String schema;
private Integer maxWaitMillis;
private boolean continueOnError = false;
private ClassLoader classLoader;
private String separator = ";";
private EmbeddedDatabaseConnection embeddedDatabaseConnection = EmbeddedDatabaseConnection.NONE;
@ -78,7 +63,7 @@ public abstract class AbstractDataSourceConfiguration implements BeanClassLoader
.get(this.classLoader);
}
protected String getDriverClassName() {
public String getDriverClassName() {
if (StringUtils.hasText(this.driverClassName)) {
return this.driverClassName;
}
@ -93,7 +78,7 @@ public abstract class AbstractDataSourceConfiguration implements BeanClassLoader
return driverClassName;
}
protected String getUrl() {
public String getUrl() {
if (StringUtils.hasText(this.url)) {
return this.url;
}
@ -108,7 +93,7 @@ public abstract class AbstractDataSourceConfiguration implements BeanClassLoader
return url;
}
protected String getUsername() {
public String getUsername() {
if (StringUtils.hasText(this.username)) {
return this.username;
}
@ -118,7 +103,7 @@ public abstract class AbstractDataSourceConfiguration implements BeanClassLoader
return null;
}
protected String getPassword() {
public String getPassword() {
if (StringUtils.hasText(this.password)) {
return this.password;
}
@ -132,10 +117,6 @@ public abstract class AbstractDataSourceConfiguration implements BeanClassLoader
this.driverClassName = driverClassName;
}
public void setInitialSize(int initialSize) {
this.initialSize = initialSize;
}
public void setUrl(String url) {
this.url = url;
}
@ -148,88 +129,48 @@ public abstract class AbstractDataSourceConfiguration implements BeanClassLoader
this.password = password;
}
public void setMaxActive(int maxActive) {
this.maxActive = maxActive;
}
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
}
public void setValidationQuery(String validationQuery) {
this.validationQuery = validationQuery;
}
public void setTestOnBorrow(boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
}
public void setTestOnReturn(boolean testOnReturn) {
this.testOnReturn = testOnReturn;
}
public void setTestWhileIdle(boolean testWhileIdle) {
this.testWhileIdle = testWhileIdle;
}
public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
}
public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
}
public void setMaxWait(int maxWaitMillis) {
this.maxWaitMillis = maxWaitMillis;
}
public int getInitialSize() {
return this.initialSize;
public boolean isInitialize() {
return this.initialize;
}
protected int getMaxActive() {
return this.maxActive;
public void setInitialize(boolean initialize) {
this.initialize = initialize;
}
protected int getMaxIdle() {
return this.maxIdle;
public String getPlatform() {
return this.platform;
}
protected int getMinIdle() {
return this.minIdle;
public void setPlatform(String platform) {
this.platform = platform;
}
protected String getValidationQuery() {
return this.validationQuery;
public String getSchema() {
return this.schema;
}
protected boolean isTestOnBorrow() {
return this.testOnBorrow;
public void setSchema(String schema) {
this.schema = schema;
}
protected boolean isTestOnReturn() {
return this.testOnReturn;
public boolean isContinueOnError() {
return this.continueOnError;
}
protected boolean isTestWhileIdle() {
return this.testWhileIdle;
public void setContinueOnError(boolean continueOnError) {
this.continueOnError = continueOnError;
}
protected Integer getTimeBetweenEvictionRunsMillis() {
return this.timeBetweenEvictionRunsMillis;
public String getSeparator() {
return this.separator;
}
protected Integer getMinEvictableIdleTimeMillis() {
return this.minEvictableIdleTimeMillis;
public void setSeparator(String separator) {
this.separator = separator;
}
protected Integer getMaxWaitMillis() {
return this.maxWaitMillis;
public ClassLoader getClassLoader() {
return this.classLoader;
}
}

@ -1,125 +0,0 @@
/*
* Copyright 2012-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.jdbc;
import java.util.Properties;
import javax.annotation.PreDestroy;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import com.zaxxer.hikari.HikariDataSource;
/**
* Configuration for a HikariCP database pool. The HikariCP pool is a popular data source
* implementation that provides high performance as well as some useful opinionated
* defaults. For compatibility with other DataSource implementations accepts configuration
* via properties in "spring.datasource.*", e.g. "url", "driverClassName", "username",
* "password" (and some others but the full list supported by the Tomcat pool is not
* applicable). Note that the Hikari team recommends using a "dataSourceClassName" and a
* Properties instance (specified here as "spring.datasource.hikari.*"). This makes the
* binding potentially vendor specific, but gives you full control of all the native
* features in the vendor's DataSource.
*
* @author Dave Syer
* @see DataSourceAutoConfiguration
* @since 1.1.0
*/
@Configuration
public class HikariDataSourceConfiguration extends AbstractDataSourceConfiguration {
private String dataSourceClassName;
private String username;
private HikariDataSource pool;
private Properties hikari = new Properties();
@Bean(destroyMethod = "shutdown")
public DataSource dataSource() {
this.pool = new HikariDataSource();
if (this.dataSourceClassName == null) {
this.pool.setDriverClassName(getDriverClassName());
}
else {
this.pool.setDataSourceClassName(this.dataSourceClassName);
this.pool.setDataSourceProperties(this.hikari);
}
this.pool.setJdbcUrl(getUrl());
if (getUsername() != null) {
this.pool.setUsername(getUsername());
}
if (getPassword() != null) {
this.pool.setPassword(getPassword());
}
this.pool.setMaximumPoolSize(getMaxActive());
this.pool.setMinimumIdle(getMinIdle());
if (isTestOnBorrow()) {
this.pool.setConnectionInitSql(getValidationQuery());
}
else {
this.pool.setConnectionTestQuery(getValidationQuery());
}
if (getMaxWaitMillis() != null) {
this.pool.setMaxLifetime(getMaxWaitMillis());
}
return this.pool;
}
@PreDestroy
public void close() {
if (this.pool != null) {
this.pool.close();
}
}
/**
* @param dataSourceClassName the dataSourceClassName to set
*/
public void setDataSourceClassName(String dataSourceClassName) {
this.dataSourceClassName = dataSourceClassName;
}
@Override
public void setUsername(String username) {
this.username = username;
}
/**
* @return the hikari data source properties
*/
public Properties getHikari() {
return this.hikari;
}
@Override
protected String getUsername() {
if (StringUtils.hasText(this.username)) {
return this.username;
}
if (this.dataSourceClassName == null
&& EmbeddedDatabaseConnection.isEmbedded(getDriverClassName())) {
return "sa";
}
return null;
}
}

@ -1,78 +0,0 @@
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.jdbc;
import javax.sql.DataSource;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.bind.PropertySourcesPropertyValues;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.ClassUtils;
/**
* @author Dave Syer
*/
public class RelaxedDataSourceFactory {
private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {
"com.zaxxer.hikari.HikariDataSource",
"org.apache.tomcat.jdbc.pool.DataSource",
"org.apache.commons.dbcp.BasicDataSource" };
private Class<? extends DataSource> type;
private ConfigurableEnvironment environment;
public static RelaxedDataSourceFactory create(ConfigurableEnvironment environment) {
return new RelaxedDataSourceFactory(environment);
}
public RelaxedDataSourceFactory(ConfigurableEnvironment environment) {
this.environment = environment;
}
public DataSource build(String prefix) {
Class<? extends DataSource> type = getType();
DataSource result = BeanUtils.instantiate(type);
RelaxedDataBinder binder = new RelaxedDataBinder(result, prefix);
binder.bind(new PropertySourcesPropertyValues(this.environment
.getPropertySources()));
return result;
}
public RelaxedDataSourceFactory type(Class<? extends DataSource> type) {
this.type = type;
return this;
}
private Class<? extends DataSource> getType() {
if (this.type != null) {
return this.type;
}
for (String name : DATA_SOURCE_TYPE_NAMES) {
if (ClassUtils.isPresent(name, null)) {
@SuppressWarnings("unchecked")
Class<DataSource> resolved = (Class<DataSource>) ClassUtils
.resolveClassName(name, null);
return resolved;
}
}
throw new IllegalStateException("No supported DataSource type found");
}
}

@ -1,89 +0,0 @@
/*
* Copyright 2012-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.jdbc;
import javax.annotation.PreDestroy;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configuration for a Tomcat database pool. The Tomcat pool provides superior performance
* and tends not to deadlock in high volume environments.
*
* @author Dave Syer
* @see DataSourceAutoConfiguration
*/
@Configuration
public class TomcatDataSourceConfiguration extends AbstractDataSourceConfiguration {
private String jdbcInterceptors;
private long validationInterval = 30000;
private org.apache.tomcat.jdbc.pool.DataSource pool;
@Bean(destroyMethod = "close")
public DataSource dataSource() {
this.pool = new org.apache.tomcat.jdbc.pool.DataSource();
this.pool.setDriverClassName(getDriverClassName());
this.pool.setUrl(getUrl());
if (getUsername() != null) {
this.pool.setUsername(getUsername());
}
if (getPassword() != null) {
this.pool.setPassword(getPassword());
}
this.pool.setInitialSize(getInitialSize());
this.pool.setMaxActive(getMaxActive());
this.pool.setMaxIdle(getMaxIdle());
this.pool.setMinIdle(getMinIdle());
this.pool.setTestOnBorrow(isTestOnBorrow());
this.pool.setTestOnReturn(isTestOnReturn());
this.pool.setTestWhileIdle(isTestWhileIdle());
if (getTimeBetweenEvictionRunsMillis() != null) {
this.pool
.setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis());
}
if (getMinEvictableIdleTimeMillis() != null) {
this.pool.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis());
}
this.pool.setValidationQuery(getValidationQuery());
this.pool.setValidationInterval(this.validationInterval);
if (getMaxWaitMillis() != null) {
this.pool.setMaxWait(getMaxWaitMillis());
}
if (this.jdbcInterceptors != null) {
this.pool.setJdbcInterceptors(this.jdbcInterceptors);
}
return this.pool;
}
@PreDestroy
public void close() {
if (this.pool != null) {
this.pool.close();
}
}
public void setJdbcInterceptors(String jdbcInterceptors) {
this.jdbcInterceptors = jdbcInterceptors;
}
public void setValidationInterval(long validationInterval) {
this.validationInterval = validationInterval;
}
}

@ -21,8 +21,12 @@ import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.junit.Test;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@ -83,4 +87,16 @@ public class CommonsDataSourceConfigurationTests {
assertEquals(GenericObjectPool.DEFAULT_MAX_WAIT, ds.getMaxWait());
}
@Configuration
@EnableConfigurationProperties
protected static class CommonsDataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX)
public DataSource dataSource() {
return DataSourceFactory.create().type(BasicDataSource.class).build();
}
}
}

@ -23,8 +23,6 @@ import java.sql.Driver;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.logging.Logger;
@ -32,15 +30,16 @@ import java.util.logging.Logger;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.MapPropertySource;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
@ -64,11 +63,17 @@ public class DataSourceAutoConfigurationTests {
@Before
public void init() {
EmbeddedDatabaseConnection.override = null;
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.initialize:false",
"spring.datasource.url:jdbc:hsqldb:mem:testdb-" + new Random().nextInt());
}
@After
public void restore() {
EmbeddedDatabaseConnection.override = null;
}
@Test
public void testDefaultDataSourceExists() throws Exception {
this.context.register(DataSourceAutoConfiguration.class,
@ -78,7 +83,36 @@ public class DataSourceAutoConfigurationTests {
}
@Test
public void testTomcatIsFallback() throws Exception {
public void testDataSourceUrlHasEmbeddedDefault() throws Exception {
this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
org.apache.tomcat.jdbc.pool.DataSource dataSource = this.context
.getBean(org.apache.tomcat.jdbc.pool.DataSource.class);
assertNotNull(dataSource.getUrl());
assertNotNull(dataSource.getDriverClassName());
}
@Test(expected = BeanCreationException.class)
public void testBadUrl() throws Exception {
EmbeddedDatabaseConnection.override = EmbeddedDatabaseConnection.NONE;
this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(DataSource.class));
}
@Test(expected = BeanCreationException.class)
public void testBadDriverClass() throws Exception {
EmbeddedDatabaseConnection.override = EmbeddedDatabaseConnection.NONE;
this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(DataSource.class));
}
@Test
public void testHikariIsFallback() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.driverClassName:org.hsqldb.jdbcDriver",
"spring.datasource.url:jdbc:hsqldb:mem:testdb");
@ -194,11 +228,12 @@ public class DataSourceAutoConfigurationTests {
public void testDataSourceInitializedWithExplicitScript() throws Exception {
this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put(DataSourceAutoConfiguration.CONFIGURATION_PREFIX + ".schema",
ClassUtils.addResourcePathToPackagePath(getClass(), "schema.sql"));
this.context.getEnvironment().getPropertySources()
.addFirst(new MapPropertySource("test", map));
EnvironmentTestUtils.addEnvironment(
this.context,
"spring.datasource.initialize:true",
"spring.datasource.schema:"
+ ClassUtils.addResourcePathToPackagePath(getClass(),
"schema.sql"));
this.context.refresh();
DataSource dataSource = this.context.getBean(DataSource.class);
assertTrue(dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource);

@ -22,10 +22,12 @@ import javax.sql.DataSource;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;
import com.zaxxer.hikari.HikariDataSource;
@ -61,8 +63,8 @@ public class HikariDataSourceConfigurationTests {
public void testDataSourcePropertiesOverridden() throws Exception {
this.context.register(HikariDataSourceConfiguration.class);
EnvironmentTestUtils.addEnvironment(this.context, PREFIX
+ "url:jdbc:foo//bar/spam");
EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "maxWait:1234");
+ "jdbcUrl:jdbc:foo//bar/spam");
EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "maxLifetime:1234");
this.context.refresh();
HikariDataSource ds = this.context.getBean(HikariDataSource.class);
assertEquals("jdbc:foo//bar/spam", ds.getJdbcUrl());
@ -74,11 +76,11 @@ public class HikariDataSourceConfigurationTests {
public void testDataSourceGenericPropertiesOverridden() throws Exception {
this.context.register(HikariDataSourceConfiguration.class);
EnvironmentTestUtils.addEnvironment(this.context, PREFIX
+ "hikari.databaseName:foo", PREFIX
+ "dataSourceClassName:org.h2.JDBCDataSource");
+ "dataSourceProperties.dataSourceClassName:org.h2.JDBCDataSource");
this.context.refresh();
HikariDataSource ds = this.context.getBean(HikariDataSource.class);
assertEquals("foo", ds.getDataSourceProperties().getProperty("databaseName"));
assertEquals("org.h2.JDBCDataSource",
ds.getDataSourceProperties().getProperty("dataSourceClassName"));
}
@Test
@ -89,28 +91,23 @@ public class HikariDataSourceConfigurationTests {
assertEquals(1800000, ds.getMaxLifetime());
}
@Test(expected = BeanCreationException.class)
public void testBadUrl() throws Exception {
EmbeddedDatabaseConnection.override = EmbeddedDatabaseConnection.NONE;
this.context.register(HikariDataSourceConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(DataSource.class));
}
@Test(expected = BeanCreationException.class)
public void testBadDriverClass() throws Exception {
EmbeddedDatabaseConnection.override = EmbeddedDatabaseConnection.NONE;
this.context.register(HikariDataSourceConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(DataSource.class));
}
@SuppressWarnings("unchecked")
public static <T> T getField(Class<?> target, String name) {
Field field = ReflectionUtils.findField(target, name, null);
ReflectionUtils.makeAccessible(field);
return (T) ReflectionUtils.getField(field, target);
}
@Configuration
@EnableConfigurationProperties
protected static class HikariDataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX)
public DataSource dataSource() {
return DataSourceFactory.create().type(HikariDataSource.class).build();
}
}
}

@ -24,11 +24,14 @@ import org.apache.tomcat.jdbc.pool.DataSourceProxy;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.test.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 org.springframework.util.ReflectionUtils;
import static org.junit.Assert.assertEquals;
@ -47,6 +50,11 @@ public class TomcatDataSourceConfigurationTests {
private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@Before
public void init() {
EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "initialize:false");
}
@After
public void restore() {
EmbeddedDatabaseConnection.override = null;
@ -115,28 +123,24 @@ public class TomcatDataSourceConfigurationTests {
assertEquals(30000L, ds.getValidationInterval());
}
@Test(expected = BeanCreationException.class)
public void testBadUrl() throws Exception {
EmbeddedDatabaseConnection.override = EmbeddedDatabaseConnection.NONE;
this.context.register(TomcatDataSourceConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(DataSource.class));
}
@Test(expected = BeanCreationException.class)
public void testBadDriverClass() throws Exception {
EmbeddedDatabaseConnection.override = EmbeddedDatabaseConnection.NONE;
this.context.register(TomcatDataSourceConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(DataSource.class));
}
@SuppressWarnings("unchecked")
public static <T> T getField(Class<?> target, String name) {
Field field = ReflectionUtils.findField(target, name, null);
ReflectionUtils.makeAccessible(field);
return (T) ReflectionUtils.getField(field, target);
}
@Configuration
@Import(DataSourceAutoConfiguration.class)
protected static class TomcatDataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX)
public DataSource dataSource() {
return DataSourceFactory.create()
.type(org.apache.tomcat.jdbc.pool.DataSource.class).build();
}
}
}

@ -40,9 +40,11 @@ dependencies {
}
compile("org.springframework.boot:spring-boot-starter-actuator")
compile("org.springframework.boot:spring-boot-starter-jdbc")
compile("org.springframework.boot:spring-boot-starter-security")
compile("org.springframework.boot:spring-boot-starter-web")
compile("com.h2database:h2")
testCompile("org.springframework.boot:spring-boot-starter-test")
insecure configurations.runtime

@ -31,6 +31,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-remote-shell</artifactId>
@ -39,6 +43,10 @@
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

@ -32,6 +32,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Integration tests for endpoints configuration.
@ -66,7 +67,6 @@ public class EndpointsPropertiesSampleActuatorApplicationTests {
ResponseEntity<String> entity = new TestRestTemplate().getForEntity(
"http://localhost:" + this.port + "/admin/health", String.class);
assertEquals(HttpStatus.OK, entity.getStatusCode());
String body = entity.getBody();
assertEquals("{\"status\":\"ok\"}", body);
assertTrue("Wrong body: " + entity.getBody(), entity.getBody().contains("\"status\":\"ok\""));
}
}

@ -33,6 +33,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Integration tests for separate management and main service ports.
@ -71,7 +72,7 @@ public class ManagementAddressActuatorApplicationTests {
"http://localhost:" + this.managementPort + "/admin/health",
String.class);
assertEquals(HttpStatus.OK, entity.getStatusCode());
assertEquals("{\"status\":\"ok\"}", entity.getBody());
assertTrue("Wrong body: " + entity.getBody(), entity.getBody().contains("\"status\":\"ok\""));
}
}

@ -33,6 +33,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Integration tests for separate management and main service ports.
@ -80,7 +81,7 @@ public class ManagementPortSampleActuatorApplicationTests {
ResponseEntity<String> entity = new TestRestTemplate().getForEntity(
"http://localhost:" + this.managementPort + "/health", String.class);
assertEquals(HttpStatus.OK, entity.getStatusCode());
assertEquals("{\"status\":\"ok\"}", entity.getBody());
assertTrue("Wrong body: " + entity.getBody(), entity.getBody().contains("\"status\":\"ok\""));
}
@Test

@ -130,7 +130,7 @@ public class SampleActuatorApplicationTests {
ResponseEntity<String> entity = new TestRestTemplate().getForEntity(
"http://localhost:" + this.port + "/health", String.class);
assertEquals(HttpStatus.OK, entity.getStatusCode());
assertEquals("{\"status\":\"ok\"}", entity.getBody());
assertTrue("Wrong body: " + entity.getBody(), entity.getBody().contains("\"status\":\"ok\""));
}
@Test

Loading…
Cancel
Save