Merge branch '2.0.x'

This commit is contained in:
Stephane Nicoll
2018-11-26 10:35:37 +01:00
6 changed files with 328 additions and 25 deletions

View File

@@ -31,6 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.jdbc.DataSourceUnwrapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jmx.export.MBeanExporter;
@@ -62,22 +63,14 @@ class DataSourceJmxConfiguration {
@PostConstruct
public void validateMBeans() {
HikariDataSource hikariDataSource = unwrapHikariDataSource();
HikariDataSource hikariDataSource = DataSourceUnwrapper
.unwrap(this.dataSource, HikariDataSource.class);
if (hikariDataSource != null && hikariDataSource.isRegisterMbeans()) {
this.mBeanExporter
.ifUnique((exporter) -> exporter.addExcludedBean("dataSource"));
}
}
private HikariDataSource unwrapHikariDataSource() {
try {
return this.dataSource.unwrap(HikariDataSource.class);
}
catch (SQLException ex) {
return null;
}
}
}
@Configuration
@@ -89,9 +82,11 @@ class DataSourceJmxConfiguration {
@Bean
@ConditionalOnMissingBean(name = "dataSourceMBean")
public Object dataSourceMBean(DataSource dataSource) {
if (dataSource instanceof DataSourceProxy) {
DataSourceProxy dataSourceProxy = DataSourceUnwrapper.unwrap(dataSource,
DataSourceProxy.class);
if (dataSourceProxy != null) {
try {
return ((DataSourceProxy) dataSource).createPool().getJmxPool();
return dataSourceProxy.createPool().getJmxPool();
}
catch (SQLException ex) {
logger.warn("Cannot expose DataSource to JMX (could not connect)");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@@ -20,6 +20,7 @@ import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.jdbc.DataSourceUnwrapper;
import org.springframework.boot.jdbc.metadata.CommonsDbcp2DataSourcePoolMetadata;
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;
import org.springframework.boot.jdbc.metadata.HikariDataSourcePoolMetadata;
@@ -44,9 +45,10 @@ public class DataSourcePoolMetadataProvidersConfiguration {
@Bean
public DataSourcePoolMetadataProvider tomcatPoolDataSourceMetadataProvider() {
return (dataSource) -> {
if (dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource) {
return new TomcatDataSourcePoolMetadata(
(org.apache.tomcat.jdbc.pool.DataSource) dataSource);
org.apache.tomcat.jdbc.pool.DataSource tomcatDataSource = DataSourceUnwrapper
.unwrap(dataSource, org.apache.tomcat.jdbc.pool.DataSource.class);
if (tomcatDataSource != null) {
return new TomcatDataSourcePoolMetadata(tomcatDataSource);
}
return null;
};
@@ -61,9 +63,10 @@ public class DataSourcePoolMetadataProvidersConfiguration {
@Bean
public DataSourcePoolMetadataProvider hikariPoolDataSourceMetadataProvider() {
return (dataSource) -> {
if (dataSource instanceof HikariDataSource) {
return new HikariDataSourcePoolMetadata(
(HikariDataSource) dataSource);
HikariDataSource hikariDataSource = DataSourceUnwrapper.unwrap(dataSource,
HikariDataSource.class);
if (hikariDataSource != null) {
return new HikariDataSourcePoolMetadata(hikariDataSource);
}
return null;
};
@@ -78,9 +81,10 @@ public class DataSourcePoolMetadataProvidersConfiguration {
@Bean
public DataSourcePoolMetadataProvider commonsDbcp2PoolDataSourceMetadataProvider() {
return (dataSource) -> {
if (dataSource instanceof BasicDataSource) {
return new CommonsDbcp2DataSourcePoolMetadata(
(BasicDataSource) dataSource);
BasicDataSource dbcpDataSource = DataSourceUnwrapper.unwrap(dataSource,
BasicDataSource.class);
if (dbcpDataSource != null) {
return new CommonsDbcp2DataSourcePoolMetadata(dbcpDataSource);
}
return null;
};

View File

@@ -38,6 +38,7 @@ import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DelegatingDataSource;
import static org.assertj.core.api.Assertions.assertThat;
@@ -45,6 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link DataSourceJmxConfiguration}.
*
* @author Stephane Nicoll
* @author Tadaya Tsuyukubo
*/
public class DataSourceJmxConfigurationTests {
@@ -155,6 +157,7 @@ public class DataSourceJmxConfigurationTests {
this.contextRunner.withPropertyValues(
"spring.datasource.type=" + DataSource.class.getName(),
"spring.datasource.jmx-enabled=true").run((context) -> {
assertThat(context).hasBean("dataSourceMBean");
assertThat(context).hasSingleBean(ConnectionPool.class);
assertThat(context.getBean(DataSourceProxy.class).createPool()
.getJmxPool())
@@ -162,6 +165,32 @@ public class DataSourceJmxConfigurationTests {
});
}
@Test
public void tomcatProxiedCanExposeMBeanPool() {
this.contextRunner.withUserConfiguration(DataSourceProxyConfiguration.class)
.withPropertyValues(
"spring.datasource.type=" + DataSource.class.getName(),
"spring.datasource.jmx-enabled=true")
.run((context) -> {
assertThat(context).hasBean("dataSourceMBean");
assertThat(context).getBean("dataSourceMBean")
.isInstanceOf(ConnectionPool.class);
});
}
@Test
public void tomcatDelegateCanExposeMBeanPool() {
this.contextRunner.withUserConfiguration(DataSourceDelegateConfiguration.class)
.withPropertyValues(
"spring.datasource.type=" + DataSource.class.getName(),
"spring.datasource.jmx-enabled=true")
.run((context) -> {
assertThat(context).hasBean("dataSourceMBean");
assertThat(context).getBean("dataSourceMBean")
.isInstanceOf(ConnectionPool.class);
});
}
@Configuration
static class DataSourceProxyConfiguration {
@@ -177,13 +206,28 @@ public class DataSourceJmxConfigurationTests {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof javax.sql.DataSource) {
return wrap((javax.sql.DataSource) bean);
return new ProxyFactory(bean).getProxy();
}
return bean;
}
private static javax.sql.DataSource wrap(javax.sql.DataSource dataSource) {
return (javax.sql.DataSource) new ProxyFactory(dataSource).getProxy();
}
@Configuration
static class DataSourceDelegateConfiguration {
@Bean
public static DataSourceBeanPostProcessor dataSourceBeanPostProcessor() {
return new DataSourceBeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean,
String beanName) {
if (bean instanceof javax.sql.DataSource) {
return new DelegatingDataSource((javax.sql.DataSource) bean);
}
return bean;
}
};
}
}