Polish DataSource metrics
This commit is contained in:
@@ -24,27 +24,24 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceMetadataProvider;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceMetadataProvidersConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvider;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} that provides
|
||||
* metrics on dataSource usage.
|
||||
* {@link EnableAutoConfiguration Auto-configuration} that provides metrics on dataSource
|
||||
* usage.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@ConditionalOnBean(DataSource.class)
|
||||
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
|
||||
@Import(DataSourceMetadataProvidersConfiguration.class)
|
||||
public class MetricDataSourceAutoConfiguration {
|
||||
public class DataSourceMetricsAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(DataSourceMetadataProvider.class)
|
||||
@ConditionalOnMissingBean(DataSourcePublicMetrics.class)
|
||||
DataSourcePublicMetrics dataSourcePublicMetrics() {
|
||||
@ConditionalOnBean(DataSourcePoolMetadataProvider.class)
|
||||
@ConditionalOnMissingBean
|
||||
public DataSourcePublicMetrics dataSourcePublicMetrics() {
|
||||
return new DataSourcePublicMetrics();
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.apache.solr.client.solrj.SolrServer;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.actuate.health.ApplicationHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.DataSourceHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthAggregator;
|
||||
@@ -36,7 +37,6 @@ import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
||||
import org.springframework.boot.actuate.health.RabbitHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.RedisHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.SolrHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.ApplicationHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
@@ -44,10 +44,10 @@ import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.jdbc.CompositeDataSourceMetadataProvider;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceMetadata;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceMetadataProvider;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadata;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvider;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProviders;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration;
|
||||
@@ -103,33 +103,36 @@ public class HealthIndicatorAutoConfiguration {
|
||||
private Map<String, DataSource> dataSources;
|
||||
|
||||
@Autowired(required = false)
|
||||
private Collection<DataSourceMetadataProvider> metadataProviders = Collections.emptyList();
|
||||
private Collection<DataSourcePoolMetadataProvider> metadataProviders = Collections
|
||||
.emptyList();
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "dbHealthIndicator")
|
||||
public HealthIndicator dbHealthIndicator() {
|
||||
DataSourceMetadataProvider metadataProvider =
|
||||
new CompositeDataSourceMetadataProvider(this.metadataProviders);
|
||||
DataSourcePoolMetadataProvider metadataProvider = new DataSourcePoolMetadataProviders(
|
||||
this.metadataProviders);
|
||||
if (this.dataSources.size() == 1) {
|
||||
return createDataSourceHealthIndicator(metadataProvider,
|
||||
this.dataSources.values().iterator().next());
|
||||
DataSource dataSource = this.dataSources.values().iterator().next();
|
||||
return createDataSourceHealthIndicator(metadataProvider, dataSource);
|
||||
}
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator(
|
||||
this.healthAggregator);
|
||||
for (Map.Entry<String, DataSource> entry : this.dataSources.entrySet()) {
|
||||
composite.addHealthIndicator(entry.getKey(),
|
||||
createDataSourceHealthIndicator(metadataProvider, entry.getValue()));
|
||||
String name = entry.getKey();
|
||||
DataSource dataSource = entry.getValue();
|
||||
composite.addHealthIndicator(name,
|
||||
createDataSourceHealthIndicator(metadataProvider, dataSource));
|
||||
}
|
||||
return composite;
|
||||
}
|
||||
|
||||
private DataSourceHealthIndicator createDataSourceHealthIndicator(DataSourceMetadataProvider provider,
|
||||
DataSource dataSource) {
|
||||
|
||||
private DataSourceHealthIndicator createDataSourceHealthIndicator(
|
||||
DataSourcePoolMetadataProvider provider, DataSource dataSource) {
|
||||
String validationQuery = null;
|
||||
DataSourceMetadata dataSourceMetadata = provider.getDataSourceMetadata(dataSource);
|
||||
if (dataSourceMetadata != null) {
|
||||
validationQuery = dataSourceMetadata.getValidationQuery();
|
||||
DataSourcePoolMetadata poolMetadata = provider
|
||||
.getDataSourcePoolMetadata(dataSource);
|
||||
if (poolMetadata != null) {
|
||||
validationQuery = poolMetadata.getValidationQuery();
|
||||
}
|
||||
return new DataSourceHealthIndicator(dataSource, validationQuery);
|
||||
}
|
||||
|
||||
@@ -20,21 +20,22 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.metrics.Metric;
|
||||
import org.springframework.boot.autoconfigure.jdbc.CompositeDataSourceMetadataProvider;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceMetadata;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceMetadataProvider;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadata;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvider;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProviders;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
/**
|
||||
* A {@link PublicMetrics} implementation that provides data source usage
|
||||
* statistics.
|
||||
* A {@link PublicMetrics} implementation that provides data source usage statistics.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
@@ -47,81 +48,66 @@ public class DataSourcePublicMetrics implements PublicMetrics {
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private Collection<DataSourceMetadataProvider> dataSourceMetadataProviders;
|
||||
private Collection<DataSourcePoolMetadataProvider> providers;
|
||||
|
||||
private final Map<String, DataSourceMetadata> dataSourceMetadataByPrefix
|
||||
= new HashMap<String, DataSourceMetadata>();
|
||||
private final Map<String, DataSourcePoolMetadata> metadataByPrefix = new HashMap<String, DataSourcePoolMetadata>();
|
||||
|
||||
@PostConstruct
|
||||
public void initialize() {
|
||||
Map<String, DataSource> dataSources = this.applicationContext.getBeansOfType(DataSource.class);
|
||||
DataSource primaryDataSource = getPrimaryDataSource();
|
||||
|
||||
|
||||
DataSourceMetadataProvider provider = new CompositeDataSourceMetadataProvider(this.dataSourceMetadataProviders);
|
||||
for (Map.Entry<String, DataSource> entry : dataSources.entrySet()) {
|
||||
String prefix = createPrefix(entry.getKey(), entry.getValue(), entry.getValue().equals(primaryDataSource));
|
||||
DataSourceMetadata dataSourceMetadata = provider.getDataSourceMetadata(entry.getValue());
|
||||
if (dataSourceMetadata != null) {
|
||||
dataSourceMetadataByPrefix.put(prefix, dataSourceMetadata);
|
||||
DataSourcePoolMetadataProvider provider = new DataSourcePoolMetadataProviders(
|
||||
this.providers);
|
||||
for (Map.Entry<String, DataSource> entry : this.applicationContext
|
||||
.getBeansOfType(DataSource.class).entrySet()) {
|
||||
String beanName = entry.getKey();
|
||||
DataSource bean = entry.getValue();
|
||||
String prefix = createPrefix(beanName, bean, bean.equals(primaryDataSource));
|
||||
DataSourcePoolMetadata poolMetadata = provider
|
||||
.getDataSourcePoolMetadata(bean);
|
||||
if (poolMetadata != null) {
|
||||
this.metadataByPrefix.put(prefix, poolMetadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Metric<?>> metrics() {
|
||||
Collection<Metric<?>> result = new LinkedHashSet<Metric<?>>();
|
||||
for (Map.Entry<String, DataSourceMetadata> entry : dataSourceMetadataByPrefix.entrySet()) {
|
||||
Set<Metric<?>> metrics = new LinkedHashSet<Metric<?>>();
|
||||
for (Map.Entry<String, DataSourcePoolMetadata> entry : this.metadataByPrefix
|
||||
.entrySet()) {
|
||||
String prefix = entry.getKey();
|
||||
// Make sure the prefix ends with a dot
|
||||
if (!prefix.endsWith(".")) {
|
||||
prefix = prefix + ".";
|
||||
}
|
||||
DataSourceMetadata dataSourceMetadata = entry.getValue();
|
||||
Integer poolSize = dataSourceMetadata.getPoolSize();
|
||||
if (poolSize != null) {
|
||||
result.add(new Metric<Integer>(prefix + "active", poolSize));
|
||||
}
|
||||
Float poolUsage = dataSourceMetadata.getPoolUsage();
|
||||
if (poolUsage != null) {
|
||||
result.add(new Metric<Float>(prefix + "usage", poolUsage));
|
||||
}
|
||||
prefix = (prefix.endsWith(".") ? prefix : prefix + ".");
|
||||
DataSourcePoolMetadata metadata = entry.getValue();
|
||||
addMetric(metrics, prefix + "max", metadata.getMax());
|
||||
addMetric(metrics, prefix + "min", metadata.getMin());
|
||||
addMetric(metrics, prefix + "active", metadata.getActive());
|
||||
addMetric(metrics, prefix + "usage", metadata.getUsage());
|
||||
}
|
||||
return metrics;
|
||||
}
|
||||
|
||||
private <T extends Number> void addMetric(Set<Metric<?>> metrics, String name, T value) {
|
||||
if (value != null) {
|
||||
metrics.add(new Metric<T>(name, value));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the prefix to use for the metrics to associate with the given {@link DataSource}.
|
||||
* @param dataSourceName the name of the data source bean
|
||||
* Create the prefix to use for the metrics to associate with the given
|
||||
* {@link DataSource}.
|
||||
* @param name the name of the data source bean
|
||||
* @param dataSource the data source to configure
|
||||
* @param primary if this data source is the primary data source
|
||||
* @return a prefix for the given data source
|
||||
*/
|
||||
protected String createPrefix(String dataSourceName, DataSource dataSource, boolean primary) {
|
||||
StringBuilder sb = new StringBuilder("datasource.");
|
||||
protected String createPrefix(String name, DataSource dataSource, boolean primary) {
|
||||
if (primary) {
|
||||
sb.append("primary");
|
||||
return "datasource.primary";
|
||||
}
|
||||
else if (endWithDataSource(dataSourceName)) { // Strip the data source part out of the name
|
||||
sb.append(dataSourceName.substring(0, dataSourceName.length() - DATASOURCE_SUFFIX.length()));
|
||||
if (name.toLowerCase().endsWith(DATASOURCE_SUFFIX.toLowerCase())) {
|
||||
name = name.substring(0, name.length() - DATASOURCE_SUFFIX.length());
|
||||
}
|
||||
else {
|
||||
sb.append(dataSourceName);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify if the given value ends with {@value #DATASOURCE_SUFFIX}.
|
||||
*/
|
||||
protected boolean endWithDataSource(String value) {
|
||||
int suffixLength = DATASOURCE_SUFFIX.length();
|
||||
int valueLength = value.length();
|
||||
if (valueLength > suffixLength) {
|
||||
String suffix = value.substring(valueLength - suffixLength, valueLength);
|
||||
return suffix.equalsIgnoreCase(DATASOURCE_SUFFIX);
|
||||
}
|
||||
return false;
|
||||
return "datasource." + name;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,9 +117,9 @@ public class DataSourcePublicMetrics implements PublicMetrics {
|
||||
*/
|
||||
private DataSource getPrimaryDataSource() {
|
||||
try {
|
||||
return applicationContext.getBean(DataSource.class);
|
||||
return this.applicationContext.getBean(DataSource.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException e) {
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.DataSourceMetricsAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration,\
|
||||
@@ -8,7 +9,6 @@ org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration,
|
||||
org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.MetricDataSourceAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.MetricRepositoryAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.TraceRepositoryAutoConfiguration,\
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
@@ -26,16 +24,15 @@ import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.apache.commons.dbcp.BasicDataSource;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.DataSourcePublicMetrics;
|
||||
import org.springframework.boot.actuate.endpoint.PublicMetrics;
|
||||
import org.springframework.boot.actuate.metrics.Metric;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -44,11 +41,17 @@ import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.ConnectionCallback;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link DataSourceMetricsAutoConfiguration}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class MetricDataSourceAutoConfigurationTests {
|
||||
public class DataSourceMetricsAutoConfigurationTests {
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@@ -78,24 +81,25 @@ public class MetricDataSourceAutoConfigurationTests {
|
||||
load(MultipleDataSourcesConfig.class);
|
||||
PublicMetrics bean = this.context.getBean(PublicMetrics.class);
|
||||
Collection<Metric<?>> metrics = bean.metrics();
|
||||
assertMetrics(metrics,
|
||||
"datasource.tomcat.active", "datasource.tomcat.usage",
|
||||
assertMetrics(metrics, "datasource.tomcat.active", "datasource.tomcat.usage",
|
||||
"datasource.commonsDbcp.active", "datasource.commonsDbcp.usage");
|
||||
|
||||
// Hikari won't work unless a first connection has been retrieved
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate(context.getBean("hikariDS", DataSource.class));
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate(this.context.getBean("hikariDS",
|
||||
DataSource.class));
|
||||
jdbcTemplate.execute(new ConnectionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInConnection(Connection connection) throws SQLException, DataAccessException {
|
||||
public Void doInConnection(Connection connection) throws SQLException,
|
||||
DataAccessException {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
Collection<Metric<?>> anotherMetrics = bean.metrics();
|
||||
assertMetrics(anotherMetrics,
|
||||
"datasource.tomcat.active", "datasource.tomcat.usage",
|
||||
"datasource.hikariDS.active", "datasource.hikariDS.usage",
|
||||
"datasource.commonsDbcp.active", "datasource.commonsDbcp.usage");
|
||||
assertMetrics(anotherMetrics, "datasource.tomcat.active",
|
||||
"datasource.tomcat.usage", "datasource.hikariDS.active",
|
||||
"datasource.hikariDS.usage", "datasource.commonsDbcp.active",
|
||||
"datasource.commonsDbcp.usage");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -103,19 +107,18 @@ public class MetricDataSourceAutoConfigurationTests {
|
||||
load(MultipleDataSourcesWithPrimaryConfig.class);
|
||||
PublicMetrics bean = this.context.getBean(PublicMetrics.class);
|
||||
Collection<Metric<?>> metrics = bean.metrics();
|
||||
assertMetrics(metrics,
|
||||
"datasource.primary.active", "datasource.primary.usage",
|
||||
assertMetrics(metrics, "datasource.primary.active", "datasource.primary.usage",
|
||||
"datasource.commonsDbcp.active", "datasource.commonsDbcp.usage");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customPrefix() {
|
||||
load(MultipleDataSourcesWithPrimaryConfig.class, CustomDataSourcePublicMetrics.class);
|
||||
load(MultipleDataSourcesWithPrimaryConfig.class,
|
||||
CustomDataSourcePublicMetrics.class);
|
||||
PublicMetrics bean = this.context.getBean(PublicMetrics.class);
|
||||
Collection<Metric<?>> metrics = bean.metrics();
|
||||
assertMetrics(metrics,
|
||||
"ds.first.active", "ds.first.usage",
|
||||
"ds.second.active", "ds.second.usage");
|
||||
assertMetrics(metrics, "ds.first.active", "ds.first.usage", "ds.second.active",
|
||||
"ds.second.usage");
|
||||
|
||||
}
|
||||
|
||||
@@ -134,17 +137,18 @@ public class MetricDataSourceAutoConfigurationTests {
|
||||
if (config.length > 0) {
|
||||
this.context.register(config);
|
||||
}
|
||||
this.context.register(MetricDataSourceAutoConfiguration.class);
|
||||
this.context.register(DataSourcePoolMetadataProvidersConfiguration.class,
|
||||
DataSourceMetricsAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class MultipleDataSourcesConfig {
|
||||
|
||||
@Bean
|
||||
public DataSource tomcatDataSource() {
|
||||
return initializeBuilder().type(org.apache.tomcat.jdbc.pool.DataSource.class).build();
|
||||
return initializeBuilder().type(org.apache.tomcat.jdbc.pool.DataSource.class)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -164,7 +168,8 @@ public class MetricDataSourceAutoConfigurationTests {
|
||||
@Bean
|
||||
@Primary
|
||||
public DataSource myDataSource() {
|
||||
return initializeBuilder().type(org.apache.tomcat.jdbc.pool.DataSource.class).build();
|
||||
return initializeBuilder().type(org.apache.tomcat.jdbc.pool.DataSource.class)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -180,7 +185,8 @@ public class MetricDataSourceAutoConfigurationTests {
|
||||
public DataSourcePublicMetrics myDataSourcePublicMetrics() {
|
||||
return new DataSourcePublicMetrics() {
|
||||
@Override
|
||||
protected String createPrefix(String dataSourceName, DataSource dataSource, boolean primary) {
|
||||
protected String createPrefix(String dataSourceName,
|
||||
DataSource dataSource, boolean primary) {
|
||||
return (primary ? "ds.first." : "ds.second");
|
||||
}
|
||||
};
|
||||
@@ -188,9 +194,8 @@ public class MetricDataSourceAutoConfigurationTests {
|
||||
}
|
||||
|
||||
private static DataSourceBuilder initializeBuilder() {
|
||||
return DataSourceBuilder.create()
|
||||
.driverClassName("org.hsqldb.jdbc.JDBCDriver")
|
||||
.url("jdbc:hsqldb:mem:test")
|
||||
.username("sa");
|
||||
return DataSourceBuilder.create().driverClassName("org.hsqldb.jdbc.JDBCDriver")
|
||||
.url("jdbc:hsqldb:mem:test").username("sa");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,9 +33,9 @@ import org.springframework.boot.actuate.health.ApplicationHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceMetadataProvidersConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration;
|
||||
@@ -167,7 +167,7 @@ public class HealthIndicatorAutoConfigurationTests {
|
||||
public void dataSourceHealthIndicatorWithCustomValidationQuery() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class, DataSourceProperties.class,
|
||||
DataSourceConfig.class, DataSourceMetadataProvidersConfiguration.class,
|
||||
DataSourceConfig.class, DataSourcePoolMetadataProvidersConfiguration.class,
|
||||
HealthIndicatorAutoConfiguration.class);
|
||||
EnvironmentTestUtils.addEnvironment(this.context, "spring.datasource.validation-query:SELECT from FOOBAR");
|
||||
this.context.refresh();
|
||||
|
||||
@@ -1,67 +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.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* A {@link DataSourceMetadataProvider} implementation that returns the first
|
||||
* {@link DataSourceMetadata} that is found by one of its delegate.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class CompositeDataSourceMetadataProvider implements DataSourceMetadataProvider {
|
||||
|
||||
private final Collection<DataSourceMetadataProvider> providers;
|
||||
|
||||
/**
|
||||
* Create an instance with an initial collection of delegates to use.
|
||||
*/
|
||||
public CompositeDataSourceMetadataProvider(Collection<DataSourceMetadataProvider> providers) {
|
||||
this.providers = providers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance with no delegate.
|
||||
*/
|
||||
public CompositeDataSourceMetadataProvider() {
|
||||
this(new ArrayList<DataSourceMetadataProvider>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSourceMetadata getDataSourceMetadata(DataSource dataSource) {
|
||||
for (DataSourceMetadataProvider provider : providers) {
|
||||
DataSourceMetadata dataSourceMetadata = provider.getDataSourceMetadata(dataSource);
|
||||
if (dataSourceMetadata != null) {
|
||||
return dataSourceMetadata;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@link DataSourceMetadataProvider} delegate to the list.
|
||||
*/
|
||||
public void addDataSourceMetadataProvider(DataSourceMetadataProvider provider) {
|
||||
this.providers.add(provider);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,6 +30,7 @@ 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.autoconfigure.jdbc.DataSourceInitializerPostProcessor.Registrar;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -54,7 +55,7 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||
@Configuration
|
||||
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
|
||||
@EnableConfigurationProperties(DataSourceProperties.class)
|
||||
@Import(Registrar.class)
|
||||
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
|
||||
public class DataSourceAutoConfiguration {
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,73 +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.sql.DataSource;
|
||||
|
||||
/**
|
||||
* Provide various metadata regarding a {@link DataSource} that
|
||||
* are shared by most data source types but not accessible in a
|
||||
* standard manner.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public interface DataSourceMetadata {
|
||||
|
||||
/**
|
||||
* Return the usage of the pool as a double value between
|
||||
* 0 and 1.
|
||||
* <ul>
|
||||
* <li>1 means that the maximum number of connections
|
||||
* have been allocated</li>
|
||||
* <li>0 means that no connection is currently active</li>
|
||||
* <li>-1 means there is not limit to the number of connections
|
||||
* that can be allocated</li>
|
||||
* </ul>
|
||||
* This may also return {@code null} if the data source does
|
||||
* not provide the necessary information to compute the poll usage.
|
||||
*/
|
||||
Float getPoolUsage();
|
||||
|
||||
/**
|
||||
* Return the current number of active connections that
|
||||
* have been allocated from the data source or {@code null}
|
||||
* if that information is not available.
|
||||
*/
|
||||
Integer getPoolSize();
|
||||
|
||||
/**
|
||||
* Return the maximum number of active connections that can be
|
||||
* allocated at the same time or {@code -1} if there is no
|
||||
* limit. Can also return {@code null} if that information is
|
||||
* not available.
|
||||
*/
|
||||
Integer getMaxPoolSize();
|
||||
|
||||
/**
|
||||
* Return the minimum number of idle connections in the pool
|
||||
* or {@code null} if that information is not available.
|
||||
*/
|
||||
Integer getMinPoolSize();
|
||||
|
||||
/**
|
||||
* Return the query to use to validate that a connection is
|
||||
* valid or {@code null} if that information is not available.
|
||||
*/
|
||||
String getValidationQuery();
|
||||
|
||||
}
|
||||
@@ -1,111 +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 com.zaxxer.hikari.HikariDataSource;
|
||||
import com.zaxxer.hikari.pool.HikariPool;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
|
||||
/**
|
||||
* A {@link DataSourceMetadata} implementation for the hikari
|
||||
* data source.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class HikariDataSourceMetadata extends AbstractDataSourceMetadata<HikariDataSource> {
|
||||
|
||||
|
||||
private final HikariPoolProvider hikariPoolProvider;
|
||||
|
||||
public HikariDataSourceMetadata(HikariDataSource dataSource) {
|
||||
super(dataSource);
|
||||
this.hikariPoolProvider = new HikariPoolProvider(dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPoolSize() {
|
||||
HikariPool hikariPool = hikariPoolProvider.getHikariPool();
|
||||
if (hikariPool != null) {
|
||||
return hikariPool.getActiveConnections();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Integer getMaxPoolSize() {
|
||||
return getDataSource().getMaximumPoolSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMinPoolSize() {
|
||||
return getDataSource().getMinimumIdle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValidationQuery() {
|
||||
return getDataSource().getConnectionTestQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the {@link HikariPool} instance managed internally by
|
||||
* the {@link HikariDataSource} as there is no other way to retrieve
|
||||
* that information except JMX access.
|
||||
*/
|
||||
private static class HikariPoolProvider {
|
||||
private final HikariDataSource dataSource;
|
||||
|
||||
private boolean poolAvailable;
|
||||
|
||||
private HikariPoolProvider(HikariDataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
this.poolAvailable = isHikariPoolAvailable();
|
||||
}
|
||||
|
||||
public HikariPool getHikariPool() {
|
||||
if (!poolAvailable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object value = doGetValue();
|
||||
if (value instanceof HikariPool) {
|
||||
return (HikariPool) value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isHikariPoolAvailable() {
|
||||
try {
|
||||
doGetValue();
|
||||
return true;
|
||||
}
|
||||
catch (BeansException e) { // No such field
|
||||
return false;
|
||||
}
|
||||
catch (SecurityException e) { // Security manager prevents to read the value
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Object doGetValue() {
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(this.dataSource);
|
||||
return accessor.getPropertyValue("pool");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,48 +14,46 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.jdbc;
|
||||
package org.springframework.boot.autoconfigure.jdbc.metadata;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* A base {@link DataSourceMetadata} implementation.
|
||||
* A base {@link DataSourcePoolMetadata} implementation.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public abstract class AbstractDataSourceMetadata<D extends DataSource> implements DataSourceMetadata {
|
||||
public abstract class AbstractDataSourcePoolMetadata<T extends DataSource> implements
|
||||
DataSourcePoolMetadata {
|
||||
|
||||
private final D dataSource;
|
||||
private final T dataSource;
|
||||
|
||||
/**
|
||||
* Create an instance with the data source to use.
|
||||
*/
|
||||
protected AbstractDataSourceMetadata(D dataSource) {
|
||||
protected AbstractDataSourcePoolMetadata(T dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getPoolUsage() {
|
||||
Integer max = getMaxPoolSize();
|
||||
if (max == null) {
|
||||
public Float getUsage() {
|
||||
Integer maxSize = getMax();
|
||||
Integer currentSize = getActive();
|
||||
if (maxSize == null || currentSize == null) {
|
||||
return null;
|
||||
}
|
||||
if (max < 0) {
|
||||
if (maxSize < 0) {
|
||||
return -1F;
|
||||
}
|
||||
Integer current = getPoolSize();
|
||||
if (current == null) {
|
||||
return null;
|
||||
}
|
||||
if (current == 0) {
|
||||
if (currentSize == 0) {
|
||||
return 0F;
|
||||
}
|
||||
return (float) current / max; // something like that
|
||||
return (float) currentSize / (float) maxSize;
|
||||
}
|
||||
|
||||
protected final D getDataSource() {
|
||||
return dataSource;
|
||||
protected final T getDataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,35 +14,37 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.jdbc;
|
||||
package org.springframework.boot.autoconfigure.jdbc.metadata;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.dbcp.BasicDataSource;
|
||||
|
||||
/**
|
||||
* A {@link DataSourceMetadata} implementation for the commons dbcp
|
||||
* data source.
|
||||
* {@link DataSourcePoolMetadata} for a Apache Commons DBCP {@link DataSource}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class CommonsDbcpDataSourceMetadata extends AbstractDataSourceMetadata<BasicDataSource> {
|
||||
public class CommonsDbcpDataSourcePoolMetadata extends
|
||||
AbstractDataSourcePoolMetadata<BasicDataSource> {
|
||||
|
||||
public CommonsDbcpDataSourceMetadata(BasicDataSource dataSource) {
|
||||
public CommonsDbcpDataSourcePoolMetadata(BasicDataSource dataSource) {
|
||||
super(dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPoolSize() {
|
||||
public Integer getActive() {
|
||||
return getDataSource().getNumActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxPoolSize() {
|
||||
public Integer getMax() {
|
||||
return getDataSource().getMaxActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMinPoolSize() {
|
||||
public Integer getMin() {
|
||||
return getDataSource().getMinIdle();
|
||||
}
|
||||
|
||||
@@ -50,4 +52,5 @@ public class CommonsDbcpDataSourceMetadata extends AbstractDataSourceMetadata<Ba
|
||||
public String getValidationQuery() {
|
||||
return getDataSource().getValidationQuery();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.metadata;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* Provides access meta-data that is commonly available from most polled
|
||||
* {@link DataSource} implementations.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public interface DataSourcePoolMetadata {
|
||||
|
||||
/**
|
||||
* Return the usage of the pool as value between 0 and 1 (or -1 if the pool is not
|
||||
* limited).
|
||||
* <ul>
|
||||
* <li>1 means that the maximum number of connections have been allocated</li>
|
||||
* <li>0 means that no connection is currently active</li>
|
||||
* <li>-1 means there is not limit to the number of connections that can be allocated</li>
|
||||
* </ul>
|
||||
* This may also return {@code null} if the data source does not provide the necessary
|
||||
* information to compute the poll usage.
|
||||
*/
|
||||
Float getUsage();
|
||||
|
||||
/**
|
||||
* Return the current number of active connections that have been allocated from the
|
||||
* data source or {@code null} if that information is not available.
|
||||
*/
|
||||
Integer getActive();
|
||||
|
||||
/**
|
||||
* Return the maximum number of active connections that can be allocated at the same
|
||||
* time or {@code -1} if there is no limit. Can also return {@code null} if that
|
||||
* information is not available.
|
||||
*/
|
||||
Integer getMax();
|
||||
|
||||
/**
|
||||
* Return the minimum number of idle connections in the pool or {@code null} if that
|
||||
* information is not available.
|
||||
*/
|
||||
Integer getMin();
|
||||
|
||||
/**
|
||||
* Return the query to use to validate that a connection is valid or {@code null} if
|
||||
* that information is not available.
|
||||
*/
|
||||
String getValidationQuery();
|
||||
|
||||
}
|
||||
@@ -14,23 +14,22 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.jdbc;
|
||||
package org.springframework.boot.autoconfigure.jdbc.metadata;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* Provide a {@link DataSourceMetadata} based on a {@link DataSource}.
|
||||
* Provide a {@link DataSourcePoolMetadata} based on a {@link DataSource}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public interface DataSourceMetadataProvider {
|
||||
public interface DataSourcePoolMetadataProvider {
|
||||
|
||||
/**
|
||||
* Return the {@link DataSourceMetadata} instance able to manage the
|
||||
* specified {@link DataSource} or {@code null} if the given data
|
||||
* source could not be handled.
|
||||
* Return the {@link DataSourcePoolMetadata} instance able to manage the specified
|
||||
* {@link DataSource} or {@code null} if the given data source could not be handled.
|
||||
*/
|
||||
DataSourceMetadata getDataSourceMetadata(DataSource dataSource);
|
||||
DataSourcePoolMetadata getDataSourcePoolMetadata(DataSource dataSource);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.metadata;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* A {@link DataSourcePoolMetadataProvider} implementation that returns the first
|
||||
* {@link DataSourcePoolMetadata} that is found by one of its delegate.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class DataSourcePoolMetadataProviders implements DataSourcePoolMetadataProvider {
|
||||
|
||||
private final List<DataSourcePoolMetadataProvider> providers;
|
||||
|
||||
/**
|
||||
* Create a {@link DataSourcePoolMetadataProviders} instance with an initial
|
||||
* collection of delegates to use.
|
||||
*/
|
||||
public DataSourcePoolMetadataProviders(
|
||||
Collection<? extends DataSourcePoolMetadataProvider> providers) {
|
||||
this.providers = new ArrayList<DataSourcePoolMetadataProvider>(providers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSourcePoolMetadata getDataSourcePoolMetadata(DataSource dataSource) {
|
||||
for (DataSourcePoolMetadataProvider provider : this.providers) {
|
||||
DataSourcePoolMetadata metadata = provider
|
||||
.getDataSourcePoolMetadata(dataSource);
|
||||
if (metadata != null) {
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,79 +14,88 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.jdbc;
|
||||
package org.springframework.boot.autoconfigure.jdbc.metadata;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.apache.commons.dbcp.BasicDataSource;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
|
||||
/**
|
||||
* Register the {@link DataSourceMetadataProvider} instances for the supported
|
||||
* data sources.
|
||||
* Register the {@link DataSourcePoolMetadataProvider} instances for the supported data
|
||||
* sources.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Configuration
|
||||
public class DataSourceMetadataProvidersConfiguration {
|
||||
public class DataSourcePoolMetadataProvidersConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
|
||||
static class TomcatDataSourceProviderConfiguration {
|
||||
static class TomcatDataSourcePoolMetadataProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
public DataSourceMetadataProvider tomcatDataSourceProvider() {
|
||||
return new DataSourceMetadataProvider() {
|
||||
public DataSourcePoolMetadataProvider tomcatPoolDataSourceMetadataProvider() {
|
||||
return new DataSourcePoolMetadataProvider() {
|
||||
@Override
|
||||
public DataSourceMetadata getDataSourceMetadata(DataSource dataSource) {
|
||||
public DataSourcePoolMetadata getDataSourcePoolMetadata(
|
||||
DataSource dataSource) {
|
||||
if (dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource) {
|
||||
return new TomcatDataSourceMetadata((org.apache.tomcat.jdbc.pool.DataSource) dataSource);
|
||||
return new TomcatDataSourcePoolMetadata(
|
||||
(org.apache.tomcat.jdbc.pool.DataSource) dataSource);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(HikariDataSource.class)
|
||||
static class HikariDataSourceProviderConfiguration {
|
||||
static class HikariPoolDataSourceMetadataProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
public DataSourceMetadataProvider hikariDataSourceProvider() {
|
||||
return new DataSourceMetadataProvider() {
|
||||
public DataSourcePoolMetadataProvider hikariPoolDataSourceMetadataProvider() {
|
||||
return new DataSourcePoolMetadataProvider() {
|
||||
@Override
|
||||
public DataSourceMetadata getDataSourceMetadata(DataSource dataSource) {
|
||||
public DataSourcePoolMetadata getDataSourcePoolMetadata(
|
||||
DataSource dataSource) {
|
||||
if (dataSource instanceof HikariDataSource) {
|
||||
return new HikariDataSourceMetadata((HikariDataSource) dataSource);
|
||||
return new HikariDataSourcePoolMetadata(
|
||||
(HikariDataSource) dataSource);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(BasicDataSource.class)
|
||||
static class CommonsDbcpDataSourceProviderConfiguration {
|
||||
static class CommonsDbcpPoolDataSourceMetadataProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
public DataSourceMetadataProvider commonsDbcpDataSourceProvider() {
|
||||
return new DataSourceMetadataProvider() {
|
||||
public DataSourcePoolMetadataProvider commonsDbcpPoolDataSourceMetadataProvider() {
|
||||
return new DataSourcePoolMetadataProvider() {
|
||||
@Override
|
||||
public DataSourceMetadata getDataSourceMetadata(DataSource dataSource) {
|
||||
public DataSourcePoolMetadata getDataSourcePoolMetadata(
|
||||
DataSource dataSource) {
|
||||
if (dataSource instanceof BasicDataSource) {
|
||||
return new CommonsDbcpDataSourceMetadata((BasicDataSource) dataSource);
|
||||
return new CommonsDbcpDataSourcePoolMetadata(
|
||||
(BasicDataSource) dataSource);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.metadata;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import com.zaxxer.hikari.pool.HikariPool;
|
||||
|
||||
/**
|
||||
* {@link DataSourcePoolMetadata} for a Hikari {@link DataSource}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class HikariDataSourcePoolMetadata extends
|
||||
AbstractDataSourcePoolMetadata<HikariDataSource> {
|
||||
|
||||
public HikariDataSourcePoolMetadata(HikariDataSource dataSource) {
|
||||
super(dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getActive() {
|
||||
try {
|
||||
return getHikariPool().getActiveConnections();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private HikariPool getHikariPool() {
|
||||
return (HikariPool) new DirectFieldAccessor(getDataSource())
|
||||
.getPropertyValue("pool");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMax() {
|
||||
return getDataSource().getMaximumPoolSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMin() {
|
||||
return getDataSource().getMinimumIdle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValidationQuery() {
|
||||
return getDataSource().getConnectionTestQuery();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,37 +14,35 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.jdbc;
|
||||
package org.springframework.boot.autoconfigure.jdbc.metadata;
|
||||
|
||||
import org.apache.tomcat.jdbc.pool.ConnectionPool;
|
||||
import org.apache.tomcat.jdbc.pool.DataSource;
|
||||
|
||||
/**
|
||||
*
|
||||
* A {@link DataSourceMetadata} implementation for the tomcat
|
||||
* data source.
|
||||
* {@link DataSourcePoolMetadata} for a Tomcat {@link DataSource}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class TomcatDataSourceMetadata extends AbstractDataSourceMetadata<DataSource> {
|
||||
public class TomcatDataSourcePoolMetadata extends AbstractDataSourcePoolMetadata<DataSource> {
|
||||
|
||||
public TomcatDataSourceMetadata(DataSource dataSource) {
|
||||
public TomcatDataSourcePoolMetadata(DataSource dataSource) {
|
||||
super(dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPoolSize() {
|
||||
public Integer getActive() {
|
||||
ConnectionPool pool = getDataSource().getPool();
|
||||
return (pool == null ? 0 : pool.getActive());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMaxPoolSize() {
|
||||
public Integer getMax() {
|
||||
return getDataSource().getMaxActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMinPoolSize() {
|
||||
public Integer getMin() {
|
||||
return getDataSource().getMinIdle();
|
||||
}
|
||||
|
||||
@@ -52,4 +50,5 @@ public class TomcatDataSourceMetadata extends AbstractDataSourceMetadata<DataSou
|
||||
public String getValidationQuery() {
|
||||
return getDataSource().getValidationQuery();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,84 +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 static org.junit.Assert.*;
|
||||
import static org.mockito.BDDMockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class CompositeDataSourceMetadataProviderTests {
|
||||
|
||||
@Mock
|
||||
private DataSourceMetadataProvider firstProvider;
|
||||
|
||||
@Mock
|
||||
private DataSourceMetadata first;
|
||||
|
||||
@Mock
|
||||
private DataSource firstDataSource;
|
||||
|
||||
@Mock
|
||||
private DataSourceMetadataProvider secondProvider;
|
||||
|
||||
@Mock
|
||||
private DataSourceMetadata second;
|
||||
|
||||
@Mock
|
||||
private DataSource secondDataSource;
|
||||
|
||||
@Mock
|
||||
private DataSource unknownDataSource;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
given(firstProvider.getDataSourceMetadata(firstDataSource)).willReturn(first);
|
||||
given(firstProvider.getDataSourceMetadata(secondDataSource)).willReturn(second);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithProviders() {
|
||||
CompositeDataSourceMetadataProvider provider =
|
||||
new CompositeDataSourceMetadataProvider(Arrays.asList(firstProvider, secondProvider));
|
||||
assertSame(first, provider.getDataSourceMetadata(firstDataSource));
|
||||
assertSame(second, provider.getDataSourceMetadata(secondDataSource));
|
||||
assertNull(provider.getDataSourceMetadata(unknownDataSource));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addProvider() {
|
||||
CompositeDataSourceMetadataProvider provider =
|
||||
new CompositeDataSourceMetadataProvider();
|
||||
assertNull(provider.getDataSourceMetadata(firstDataSource));
|
||||
provider.addDataSourceMetadataProvider(firstProvider);
|
||||
assertSame(first, provider.getDataSourceMetadata(firstDataSource));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,24 +14,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.jdbc;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
package org.springframework.boot.autoconfigure.jdbc.metadata;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.ConnectionCallback;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Abstract base class for {@link DataSourcePoolMetadata} tests.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public abstract class AbstractDataSourceMetadataTests<D extends AbstractDataSourceMetadata> {
|
||||
public abstract class AbstractDataSourcePoolMetadataTests<D extends AbstractDataSourcePoolMetadata<?>> {
|
||||
|
||||
/**
|
||||
* Return a data source metadata instance with a min size of 0 and max size of 2.
|
||||
@@ -40,36 +41,40 @@ public abstract class AbstractDataSourceMetadataTests<D extends AbstractDataSour
|
||||
|
||||
@Test
|
||||
public void getMaxPoolSize() {
|
||||
assertEquals(Integer.valueOf(2), getDataSourceMetadata().getMaxPoolSize());
|
||||
assertEquals(Integer.valueOf(2), getDataSourceMetadata().getMax());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMinPoolSize() {
|
||||
assertEquals(Integer.valueOf(0), getDataSourceMetadata().getMinPoolSize());
|
||||
assertEquals(Integer.valueOf(0), getDataSourceMetadata().getMin());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPoolSizeNoConnection() {
|
||||
// Make sure the pool is initialized
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceMetadata().getDataSource());
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceMetadata()
|
||||
.getDataSource());
|
||||
jdbcTemplate.execute(new ConnectionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInConnection(Connection connection) throws SQLException, DataAccessException {
|
||||
public Void doInConnection(Connection connection) throws SQLException,
|
||||
DataAccessException {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
assertEquals(Integer.valueOf(0), getDataSourceMetadata().getPoolSize());
|
||||
assertEquals(Float.valueOf(0), getDataSourceMetadata().getPoolUsage());
|
||||
assertEquals(Integer.valueOf(0), getDataSourceMetadata().getActive());
|
||||
assertEquals(Float.valueOf(0), getDataSourceMetadata().getUsage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPoolSizeOneConnection() {
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceMetadata().getDataSource());
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceMetadata()
|
||||
.getDataSource());
|
||||
jdbcTemplate.execute(new ConnectionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInConnection(Connection connection) throws SQLException, DataAccessException {
|
||||
assertEquals(Integer.valueOf(1), getDataSourceMetadata().getPoolSize());
|
||||
assertEquals(Float.valueOf(0.5F), getDataSourceMetadata().getPoolUsage());
|
||||
public Void doInConnection(Connection connection) throws SQLException,
|
||||
DataAccessException {
|
||||
assertEquals(Integer.valueOf(1), getDataSourceMetadata().getActive());
|
||||
assertEquals(Float.valueOf(0.5F), getDataSourceMetadata().getUsage());
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@@ -77,15 +82,20 @@ public abstract class AbstractDataSourceMetadataTests<D extends AbstractDataSour
|
||||
|
||||
@Test
|
||||
public void getPoolSizeTwoConnections() {
|
||||
final JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceMetadata().getDataSource());
|
||||
final JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceMetadata()
|
||||
.getDataSource());
|
||||
jdbcTemplate.execute(new ConnectionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInConnection(Connection connection) throws SQLException, DataAccessException {
|
||||
public Void doInConnection(Connection connection) throws SQLException,
|
||||
DataAccessException {
|
||||
jdbcTemplate.execute(new ConnectionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInConnection(Connection connection) throws SQLException, DataAccessException {
|
||||
assertEquals(Integer.valueOf(2), getDataSourceMetadata().getPoolSize());
|
||||
assertEquals(Float.valueOf(1F), getDataSourceMetadata().getPoolUsage());
|
||||
public Void doInConnection(Connection connection)
|
||||
throws SQLException, DataAccessException {
|
||||
assertEquals(Integer.valueOf(2), getDataSourceMetadata()
|
||||
.getActive());
|
||||
assertEquals(Float.valueOf(1F), getDataSourceMetadata()
|
||||
.getUsage());
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@@ -98,10 +108,8 @@ public abstract class AbstractDataSourceMetadataTests<D extends AbstractDataSour
|
||||
public abstract void getValidationQuery();
|
||||
|
||||
protected DataSourceBuilder initializeBuilder() {
|
||||
return DataSourceBuilder.create()
|
||||
.driverClassName("org.hsqldb.jdbc.JDBCDriver")
|
||||
.url("jdbc:hsqldb:mem:test")
|
||||
.username("sa");
|
||||
return DataSourceBuilder.create().driverClassName("org.hsqldb.jdbc.JDBCDriver")
|
||||
.url("jdbc:hsqldb:mem:test").username("sa");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,21 +14,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.jdbc;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
package org.springframework.boot.autoconfigure.jdbc.metadata;
|
||||
|
||||
import org.apache.commons.dbcp.BasicDataSource;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.CommonsDbcpDataSourcePoolMetadata;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadata;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
/**
|
||||
* Tests for {@link CommonsDbcpDataSourcePoolMetadata}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class CommonsDbcpDataSourceMetadataTests extends AbstractDataSourceMetadataTests<CommonsDbcpDataSourceMetadata> {
|
||||
public class CommonsDbcpDataSourcePoolMetadataTests extends
|
||||
AbstractDataSourcePoolMetadataTests<CommonsDbcpDataSourcePoolMetadata> {
|
||||
|
||||
private CommonsDbcpDataSourceMetadata dataSourceMetadata;
|
||||
private CommonsDbcpDataSourcePoolMetadata dataSourceMetadata;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
@@ -36,50 +41,54 @@ public class CommonsDbcpDataSourceMetadataTests extends AbstractDataSourceMetada
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CommonsDbcpDataSourceMetadata getDataSourceMetadata() {
|
||||
protected CommonsDbcpDataSourcePoolMetadata getDataSourceMetadata() {
|
||||
return this.dataSourceMetadata;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPoolUsageWithNoCurrent() {
|
||||
CommonsDbcpDataSourceMetadata dsm = new CommonsDbcpDataSourceMetadata(createDataSource()) {
|
||||
CommonsDbcpDataSourcePoolMetadata dsm = new CommonsDbcpDataSourcePoolMetadata(
|
||||
createDataSource()) {
|
||||
@Override
|
||||
public Integer getPoolSize() {
|
||||
public Integer getActive() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
assertNull(dsm.getPoolUsage());
|
||||
assertNull(dsm.getUsage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPoolUsageWithNoMax() {
|
||||
CommonsDbcpDataSourceMetadata dsm = new CommonsDbcpDataSourceMetadata(createDataSource()) {
|
||||
CommonsDbcpDataSourcePoolMetadata dsm = new CommonsDbcpDataSourcePoolMetadata(
|
||||
createDataSource()) {
|
||||
@Override
|
||||
public Integer getMaxPoolSize() {
|
||||
public Integer getMax() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
assertNull(dsm.getPoolUsage());
|
||||
assertNull(dsm.getUsage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPoolUsageWithUnlimitedPool() {
|
||||
DataSourceMetadata unlimitedDataSource = createDataSourceMetadata(0, -1);
|
||||
assertEquals(Float.valueOf(-1F), unlimitedDataSource.getPoolUsage());
|
||||
DataSourcePoolMetadata unlimitedDataSource = createDataSourceMetadata(0, -1);
|
||||
assertEquals(Float.valueOf(-1F), unlimitedDataSource.getUsage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getValidationQuery() {
|
||||
BasicDataSource dataSource = createDataSource();
|
||||
dataSource.setValidationQuery("SELECT FROM FOO");
|
||||
assertEquals("SELECT FROM FOO", new CommonsDbcpDataSourceMetadata(dataSource).getValidationQuery());
|
||||
assertEquals("SELECT FROM FOO",
|
||||
new CommonsDbcpDataSourcePoolMetadata(dataSource).getValidationQuery());
|
||||
}
|
||||
|
||||
private CommonsDbcpDataSourceMetadata createDataSourceMetadata(int minSize, int maxSize) {
|
||||
private CommonsDbcpDataSourcePoolMetadata createDataSourceMetadata(int minSize,
|
||||
int maxSize) {
|
||||
BasicDataSource dataSource = createDataSource();
|
||||
dataSource.setMinIdle(minSize);
|
||||
dataSource.setMaxActive(maxSize);
|
||||
return new CommonsDbcpDataSourceMetadata(dataSource);
|
||||
return new CommonsDbcpDataSourcePoolMetadata(dataSource);
|
||||
}
|
||||
|
||||
private BasicDataSource createDataSource() {
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.metadata;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
||||
/**
|
||||
* Tests for {@link DataSourcePoolMetadataProviders}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class DataSourcePoolMetadataProvidersTests {
|
||||
|
||||
@Mock
|
||||
private DataSourcePoolMetadataProvider firstProvider;
|
||||
|
||||
@Mock
|
||||
private DataSourcePoolMetadata first;
|
||||
|
||||
@Mock
|
||||
private DataSource firstDataSource;
|
||||
|
||||
@Mock
|
||||
private DataSourcePoolMetadataProvider secondProvider;
|
||||
|
||||
@Mock
|
||||
private DataSourcePoolMetadata second;
|
||||
|
||||
@Mock
|
||||
private DataSource secondDataSource;
|
||||
|
||||
@Mock
|
||||
private DataSource unknownDataSource;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
given(this.firstProvider.getDataSourcePoolMetadata(this.firstDataSource))
|
||||
.willReturn(this.first);
|
||||
given(this.firstProvider.getDataSourcePoolMetadata(this.secondDataSource))
|
||||
.willReturn(this.second);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithProviders() {
|
||||
DataSourcePoolMetadataProviders provider = new DataSourcePoolMetadataProviders(
|
||||
Arrays.asList(this.firstProvider, this.secondProvider));
|
||||
assertSame(this.first, provider.getDataSourcePoolMetadata(this.firstDataSource));
|
||||
assertSame(this.second, provider.getDataSourcePoolMetadata(this.secondDataSource));
|
||||
assertNull(provider.getDataSourcePoolMetadata(this.unknownDataSource));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,27 +14,32 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.jdbc;
|
||||
package org.springframework.boot.autoconfigure.jdbc.metadata;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.HikariDataSourcePoolMetadata;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.junit.Before;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests for {@link HikariDataSourcePoolMetadata}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class HikariDataSourceMetadataTests extends AbstractDataSourceMetadataTests<HikariDataSourceMetadata> {
|
||||
public class HikariDataSourcePoolMetadataTests extends
|
||||
AbstractDataSourcePoolMetadataTests<HikariDataSourcePoolMetadata> {
|
||||
|
||||
private HikariDataSourceMetadata dataSourceMetadata;
|
||||
private HikariDataSourcePoolMetadata dataSourceMetadata;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.dataSourceMetadata = new HikariDataSourceMetadata(createDataSource(0, 2));
|
||||
this.dataSourceMetadata = new HikariDataSourcePoolMetadata(createDataSource(0, 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HikariDataSourceMetadata getDataSourceMetadata() {
|
||||
protected HikariDataSourcePoolMetadata getDataSourceMetadata() {
|
||||
return this.dataSourceMetadata;
|
||||
}
|
||||
|
||||
@@ -42,11 +47,13 @@ public class HikariDataSourceMetadataTests extends AbstractDataSourceMetadataTes
|
||||
public void getValidationQuery() {
|
||||
HikariDataSource dataSource = createDataSource(0, 4);
|
||||
dataSource.setConnectionTestQuery("SELECT FROM FOO");
|
||||
assertEquals("SELECT FROM FOO", new HikariDataSourceMetadata(dataSource).getValidationQuery());
|
||||
assertEquals("SELECT FROM FOO",
|
||||
new HikariDataSourcePoolMetadata(dataSource).getValidationQuery());
|
||||
}
|
||||
|
||||
private HikariDataSource createDataSource(int minSize, int maxSize) {
|
||||
HikariDataSource dataSource = (HikariDataSource) initializeBuilder().type(HikariDataSource.class).build();
|
||||
HikariDataSource dataSource = (HikariDataSource) initializeBuilder().type(
|
||||
HikariDataSource.class).build();
|
||||
dataSource.setMinimumIdle(minSize);
|
||||
dataSource.setMaximumPoolSize(maxSize);
|
||||
return dataSource;
|
||||
@@ -14,28 +14,31 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.jdbc;
|
||||
package org.springframework.boot.autoconfigure.jdbc.metadata;
|
||||
|
||||
import org.apache.tomcat.jdbc.pool.DataSource;
|
||||
import org.junit.Before;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.TomcatDataSourcePoolMetadata;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests for {@link TomcatDataSourcePoolMetadata}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class TomcatDataSourceMetadataTests extends AbstractDataSourceMetadataTests<TomcatDataSourceMetadata> {
|
||||
public class TomcatDataSourcePoolMetadataTests extends
|
||||
AbstractDataSourcePoolMetadataTests<TomcatDataSourcePoolMetadata> {
|
||||
|
||||
private TomcatDataSourceMetadata dataSourceMetadata;
|
||||
private TomcatDataSourcePoolMetadata dataSourceMetadata;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.dataSourceMetadata = new TomcatDataSourceMetadata(createDataSource(0, 2));
|
||||
this.dataSourceMetadata = new TomcatDataSourcePoolMetadata(createDataSource(0, 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TomcatDataSourceMetadata getDataSourceMetadata() {
|
||||
protected TomcatDataSourcePoolMetadata getDataSourceMetadata() {
|
||||
return this.dataSourceMetadata;
|
||||
}
|
||||
|
||||
@@ -43,11 +46,13 @@ public class TomcatDataSourceMetadataTests extends AbstractDataSourceMetadataTes
|
||||
public void getValidationQuery() {
|
||||
DataSource dataSource = createDataSource(0, 4);
|
||||
dataSource.setValidationQuery("SELECT FROM FOO");
|
||||
assertEquals("SELECT FROM FOO", new TomcatDataSourceMetadata(dataSource).getValidationQuery());
|
||||
assertEquals("SELECT FROM FOO",
|
||||
new TomcatDataSourcePoolMetadata(dataSource).getValidationQuery());
|
||||
}
|
||||
|
||||
private DataSource createDataSource(int minSize, int maxSize) {
|
||||
DataSource dataSource = (DataSource) initializeBuilder().type(DataSource.class).build();
|
||||
DataSource dataSource = (DataSource) initializeBuilder().type(DataSource.class)
|
||||
.build();
|
||||
dataSource.setMinIdle(minSize);
|
||||
dataSource.setMaxActive(maxSize);
|
||||
|
||||
@@ -634,26 +634,35 @@ The `gauge` shows the last response time for a request. So the last request to `
|
||||
NOTE: In this example we are actually accessing the endpoint over HTTP using the
|
||||
`/metrics` URL, this explains why `metrics` appears in the response.
|
||||
|
||||
|
||||
|
||||
[[production-ready-datasource-metrics]]
|
||||
=== DataSource metrics
|
||||
The following metrics are exposed for each supported `DataSource` defined in your
|
||||
application:
|
||||
|
||||
The following metrics are available for each data source defined in the application: the
|
||||
number of allocated connection(s) (`.active`) and the current usage of the connection
|
||||
pool (`.usage`).
|
||||
* The maximum number connections (`datasource.xxx.max`).
|
||||
* The minimum number of connections (`datasource.xxx.min`).
|
||||
* The number of active connections (`datasource.xxx.active`)
|
||||
* The current usage of the connection pool (`datasource.xxx.usage`).
|
||||
|
||||
All data source metrics share the `datasource.` prefix. The prefix is further qualified for
|
||||
each data source:
|
||||
All data source metrics share the `datasource.` prefix. The prefix is further qualified
|
||||
for each data source:
|
||||
|
||||
* If the data source is the primary data source (that is either the only available data
|
||||
source or the one flagged `@Primary` amongst the existing ones), the prefix is `datasource.primary`
|
||||
* If the data source bean name ends with `dataSource`, the prefix is the name of the bean without
|
||||
it (i.e. `datasource.batch` for `batchDataSource`)
|
||||
* In all other cases, the name of the bean is used
|
||||
source or the one flagged `@Primary` amongst the existing ones), the prefix is
|
||||
`datasource.primary`.
|
||||
* If the data source bean name ends with `dataSource`, the prefix is the name of the bean
|
||||
without `dataSource` (i.e. `datasource.batch` for `batchDataSource`).
|
||||
* In all other cases, the name of the bean is used.
|
||||
|
||||
It is possible to override part or all of those defaults by registering a bean with a
|
||||
customized version of `DataSourcePublicMetrics`. By default, Spring Boot provides metadata
|
||||
for all supported datasources; you can add additional `DataSourcePoolMetadataProvider`
|
||||
beans if your favorite data source isn't supported out of the box. See
|
||||
`DataSourcePoolMetadataProvidersConfiguration` for examples.
|
||||
|
||||
|
||||
It is possible to override part or all of those defaults by registering a bean with a customized
|
||||
version of `DataSourcePublicMetrics`. Spring Boot provides those metadata for all supported
|
||||
datasource; you can provide a `DataSourceMetadata` implementation for your favorite data source,
|
||||
check `DatasourceMetadataProvidersConfiguration` for more details.
|
||||
|
||||
[[production-ready-recording-metrics]]
|
||||
=== Recording your own metrics
|
||||
|
||||
Reference in New Issue
Block a user