pull/1487/head
Phillip Webb 10 years ago
parent 2262a3baa7
commit c8809afe1b

@ -20,12 +20,14 @@ import java.sql.Connection;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.DataAccessUtils; import org.springframework.dao.support.DataAccessUtils;
import org.springframework.jdbc.IncorrectResultSetColumnCountException; import org.springframework.jdbc.IncorrectResultSetColumnCountException;
@ -33,6 +35,7 @@ import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.JdbcUtils; import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -45,24 +48,26 @@ import org.springframework.util.StringUtils;
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 1.1.0 * @since 1.1.0
*/ */
public class DataSourceHealthIndicator extends AbstractHealthIndicator { public class DataSourceHealthIndicator extends AbstractHealthIndicator implements
InitializingBean {
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
private static final Map<String, String> queries = new HashMap<String, String>();
private static final Map<String, String> PRODUCT_SPECIFIC_QUERIES;
static { static {
Map<String, String> queries = new HashMap<String, String>();
queries.put("HSQL Database Engine", "SELECT COUNT(*) FROM " queries.put("HSQL Database Engine", "SELECT COUNT(*) FROM "
+ "INFORMATION_SCHEMA.SYSTEM_USERS"); + "INFORMATION_SCHEMA.SYSTEM_USERS");
queries.put("Oracle", "SELECT 'Hello' from DUAL"); queries.put("Oracle", "SELECT 'Hello' from DUAL");
queries.put("Apache Derby", "SELECT 1 FROM SYSIBM.SYSDUMMY1"); queries.put("Apache Derby", "SELECT 1 FROM SYSIBM.SYSDUMMY1");
PRODUCT_SPECIFIC_QUERIES = Collections.unmodifiableMap(queries);
} }
private static final String DEFAULT_QUERY = "SELECT 1"; private static final String DEFAULT_QUERY = "SELECT 1";
private String query = null; private DataSource dataSource;
private String query;
private JdbcTemplate jdbcTemplate;
/** /**
* Create a new {@link DataSourceHealthIndicator} instance. * Create a new {@link DataSourceHealthIndicator} instance.
@ -71,7 +76,17 @@ public class DataSourceHealthIndicator extends AbstractHealthIndicator {
} }
/** /**
* Create a new {@link DataSourceHealthIndicator} using the specified datasource. * Create a new {@link DataSourceHealthIndicator} using the specified
* {@link DataSource}.
* @param dataSource the data source
*/
public DataSourceHealthIndicator(DataSource dataSource) {
this(dataSource, null);
}
/**
* Create a new {@link DataSourceHealthIndicator} using the specified
* {@link DataSource} and validation query.
* @param dataSource the data source * @param dataSource the data source
* @param query the validation query to use (can be {@code null}) * @param query the validation query to use (can be {@code null})
*/ */
@ -81,12 +96,10 @@ public class DataSourceHealthIndicator extends AbstractHealthIndicator {
this.jdbcTemplate = new JdbcTemplate(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource);
} }
/** @Override
* Create a new {@link DataSourceHealthIndicator} using the specified datasource. public void afterPropertiesSet() throws Exception {
* @param dataSource the data source Assert.state(this.dataSource != null,
*/ "DataSource for DataSourceHealthIndicator must be specified");
public DataSourceHealthIndicator(DataSource dataSource) {
this(dataSource, null);
} }
@Override @Override
@ -102,11 +115,11 @@ public class DataSourceHealthIndicator extends AbstractHealthIndicator {
private void doDataSourceHealthCheck(Health.Builder builder) throws Exception { private void doDataSourceHealthCheck(Health.Builder builder) throws Exception {
String product = getProduct(); String product = getProduct();
builder.up().withDetail("database", product); builder.up().withDetail("database", product);
String query = detectQuery(product); String validationQuery = getValidationQuery(product);
if (StringUtils.hasText(query)) { if (StringUtils.hasText(validationQuery)) {
try { try {
// Avoid calling getObject as it breaks MySQL on Java 7 // Avoid calling getObject as it breaks MySQL on Java 7
List<Object> results = this.jdbcTemplate.query(query, List<Object> results = this.jdbcTemplate.query(validationQuery,
new SingleColumnRowMapper()); new SingleColumnRowMapper());
Object result = DataAccessUtils.requiredSingleResult(results); Object result = DataAccessUtils.requiredSingleResult(results);
builder.withDetail("hello", result); builder.withDetail("hello", result);
@ -127,10 +140,10 @@ public class DataSourceHealthIndicator extends AbstractHealthIndicator {
}); });
} }
protected String detectQuery(String product) { protected String getValidationQuery(String product) {
String query = this.query; String query = this.query;
if (!StringUtils.hasText(query)) { if (!StringUtils.hasText(query)) {
query = queries.get(product); query = PRODUCT_SPECIFIC_QUERIES.get(product);
} }
if (!StringUtils.hasText(query)) { if (!StringUtils.hasText(query)) {
query = DEFAULT_QUERY; query = DEFAULT_QUERY;
@ -147,18 +160,18 @@ public class DataSourceHealthIndicator extends AbstractHealthIndicator {
} }
/** /**
* Set a specific validation query to use to validate a connection. If * Set a specific validation query to use to validate a connection. If none is set, a
* none is set, a default validation query is used. * default validation query is used.
*/ */
public void setQuery(String query) { public void setQuery(String query) {
this.query = query; this.query = query;
} }
/** /**
* Return the specific validation query, if any. * Return the validation query or {@code null}.
*/ */
public String getQuery() { public String getQuery() {
return query; return this.query;
} }
/** /**

@ -23,13 +23,13 @@ import javax.sql.DataSource;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.actuate.health.ApplicationHealthIndicator;
import org.springframework.boot.actuate.health.DataSourceHealthIndicator; import org.springframework.boot.actuate.health.DataSourceHealthIndicator;
import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.MongoHealthIndicator; import org.springframework.boot.actuate.health.MongoHealthIndicator;
import org.springframework.boot.actuate.health.RabbitHealthIndicator; import org.springframework.boot.actuate.health.RabbitHealthIndicator;
import org.springframework.boot.actuate.health.RedisHealthIndicator; import org.springframework.boot.actuate.health.RedisHealthIndicator;
import org.springframework.boot.actuate.health.SolrHealthIndicator; import org.springframework.boot.actuate.health.SolrHealthIndicator;
import org.springframework.boot.actuate.health.ApplicationHealthIndicator;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration; import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
@ -166,12 +166,15 @@ public class HealthIndicatorAutoConfigurationTests {
@Test @Test
public void dataSourceHealthIndicatorWithCustomValidationQuery() { public void dataSourceHealthIndicatorWithCustomValidationQuery() {
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
this.context.register(PropertyPlaceholderAutoConfiguration.class, DataSourceProperties.class, this.context.register(PropertyPlaceholderAutoConfiguration.class,
DataSourceConfig.class, DataSourcePoolMetadataProvidersConfiguration.class, DataSourceProperties.class, DataSourceConfig.class,
DataSourcePoolMetadataProvidersConfiguration.class,
HealthIndicatorAutoConfiguration.class); HealthIndicatorAutoConfiguration.class);
EnvironmentTestUtils.addEnvironment(this.context, "spring.datasource.validation-query:SELECT from FOOBAR"); EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.validation-query:SELECT from FOOBAR");
this.context.refresh(); this.context.refresh();
Map<String, HealthIndicator> beans = this.context.getBeansOfType(HealthIndicator.class); Map<String, HealthIndicator> beans = this.context
.getBeansOfType(HealthIndicator.class);
assertEquals(1, beans.size()); assertEquals(1, beans.size());
HealthIndicator healthIndicator = beans.values().iterator().next(); HealthIndicator healthIndicator = beans.values().iterator().next();
assertEquals(DataSourceHealthIndicator.class, healthIndicator.getClass()); assertEquals(DataSourceHealthIndicator.class, healthIndicator.getClass());
@ -247,7 +250,6 @@ public class HealthIndicatorAutoConfigurationTests {
.getClass()); .getClass());
} }
@Configuration @Configuration
@EnableConfigurationProperties @EnableConfigurationProperties
protected static class DataSourceConfig { protected static class DataSourceConfig {
@ -257,8 +259,9 @@ public class HealthIndicatorAutoConfigurationTests {
public DataSource dataSource() { public DataSource dataSource() {
return DataSourceBuilder.create() return DataSourceBuilder.create()
.driverClassName("org.hsqldb.jdbc.JDBCDriver") .driverClassName("org.hsqldb.jdbc.JDBCDriver")
.url("jdbc:hsqldb:mem:test") .url("jdbc:hsqldb:mem:test").username("sa").build();
.username("sa").build();
} }
} }
} }

Loading…
Cancel
Save