Merge branch '2.4.x'

Closes gh-24842
pull/24849/head
Stephane Nicoll 4 years ago
commit a788ef4958

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,6 +24,7 @@ import java.util.stream.Collectors;
import javax.sql.DataSource; import javax.sql.DataSource;
import com.zaxxer.hikari.HikariConfigMXBean;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.metrics.micrometer.MicrometerMetricsTrackerFactory; import com.zaxxer.hikari.metrics.micrometer.MicrometerMetricsTrackerFactory;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MeterRegistry;
@ -112,7 +113,8 @@ public class DataSourcePoolMetricsAutoConfiguration {
@Autowired @Autowired
void bindMetricsRegistryToHikariDataSources(Collection<DataSource> dataSources) { void bindMetricsRegistryToHikariDataSources(Collection<DataSource> dataSources) {
for (DataSource dataSource : dataSources) { for (DataSource dataSource : dataSources) {
HikariDataSource hikariDataSource = DataSourceUnwrapper.unwrap(dataSource, HikariDataSource.class); HikariDataSource hikariDataSource = DataSourceUnwrapper.unwrap(dataSource, HikariConfigMXBean.class,
HikariDataSource.class);
if (hikariDataSource != null) { if (hikariDataSource != null) {
bindMetricsRegistryToHikariDataSource(hikariDataSource); bindMetricsRegistryToHikariDataSource(hikariDataSource);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,10 +20,12 @@ import java.sql.SQLException;
import javax.sql.DataSource; import javax.sql.DataSource;
import com.zaxxer.hikari.HikariConfigMXBean;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.tomcat.jdbc.pool.DataSourceProxy; import org.apache.tomcat.jdbc.pool.DataSourceProxy;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@ -62,7 +64,8 @@ class DataSourceJmxConfiguration {
} }
private void validateMBeans() { private void validateMBeans() {
HikariDataSource hikariDataSource = DataSourceUnwrapper.unwrap(this.dataSource, HikariDataSource.class); HikariDataSource hikariDataSource = DataSourceUnwrapper.unwrap(this.dataSource, HikariConfigMXBean.class,
HikariDataSource.class);
if (hikariDataSource != null && hikariDataSource.isRegisterMbeans()) { if (hikariDataSource != null && hikariDataSource.isRegisterMbeans()) {
this.mBeanExporter.ifUnique((exporter) -> exporter.addExcludedBean("dataSource")); this.mBeanExporter.ifUnique((exporter) -> exporter.addExcludedBean("dataSource"));
} }
@ -79,7 +82,8 @@ class DataSourceJmxConfiguration {
@Bean @Bean
@ConditionalOnMissingBean(name = "dataSourceMBean") @ConditionalOnMissingBean(name = "dataSourceMBean")
Object dataSourceMBean(DataSource dataSource) { Object dataSourceMBean(DataSource dataSource) {
DataSourceProxy dataSourceProxy = DataSourceUnwrapper.unwrap(dataSource, DataSourceProxy.class); DataSourceProxy dataSourceProxy = DataSourceUnwrapper.unwrap(dataSource, PoolConfiguration.class,
DataSourceProxy.class);
if (dataSourceProxy != null) { if (dataSourceProxy != null) {
try { try {
return dataSourceProxy.createPool().getJmxPool(); return dataSourceProxy.createPool().getJmxPool();

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,10 +16,13 @@
package org.springframework.boot.autoconfigure.jdbc.metadata; package org.springframework.boot.autoconfigure.jdbc.metadata;
import com.zaxxer.hikari.HikariConfigMXBean;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import oracle.jdbc.OracleConnection; import oracle.jdbc.OracleConnection;
import oracle.ucp.jdbc.PoolDataSource; import oracle.ucp.jdbc.PoolDataSource;
import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceMXBean;
import org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.jdbc.DataSourceUnwrapper; import org.springframework.boot.jdbc.DataSourceUnwrapper;
@ -50,7 +53,7 @@ public class DataSourcePoolMetadataProvidersConfiguration {
DataSourcePoolMetadataProvider tomcatPoolDataSourceMetadataProvider() { DataSourcePoolMetadataProvider tomcatPoolDataSourceMetadataProvider() {
return (dataSource) -> { return (dataSource) -> {
org.apache.tomcat.jdbc.pool.DataSource tomcatDataSource = DataSourceUnwrapper.unwrap(dataSource, org.apache.tomcat.jdbc.pool.DataSource tomcatDataSource = DataSourceUnwrapper.unwrap(dataSource,
org.apache.tomcat.jdbc.pool.DataSource.class); ConnectionPoolMBean.class, org.apache.tomcat.jdbc.pool.DataSource.class);
if (tomcatDataSource != null) { if (tomcatDataSource != null) {
return new TomcatDataSourcePoolMetadata(tomcatDataSource); return new TomcatDataSourcePoolMetadata(tomcatDataSource);
} }
@ -67,7 +70,8 @@ public class DataSourcePoolMetadataProvidersConfiguration {
@Bean @Bean
DataSourcePoolMetadataProvider hikariPoolDataSourceMetadataProvider() { DataSourcePoolMetadataProvider hikariPoolDataSourceMetadataProvider() {
return (dataSource) -> { return (dataSource) -> {
HikariDataSource hikariDataSource = DataSourceUnwrapper.unwrap(dataSource, HikariDataSource.class); HikariDataSource hikariDataSource = DataSourceUnwrapper.unwrap(dataSource, HikariConfigMXBean.class,
HikariDataSource.class);
if (hikariDataSource != null) { if (hikariDataSource != null) {
return new HikariDataSourcePoolMetadata(hikariDataSource); return new HikariDataSourcePoolMetadata(hikariDataSource);
} }
@ -84,7 +88,8 @@ public class DataSourcePoolMetadataProvidersConfiguration {
@Bean @Bean
DataSourcePoolMetadataProvider commonsDbcp2PoolDataSourceMetadataProvider() { DataSourcePoolMetadataProvider commonsDbcp2PoolDataSourceMetadataProvider() {
return (dataSource) -> { return (dataSource) -> {
BasicDataSource dbcpDataSource = DataSourceUnwrapper.unwrap(dataSource, BasicDataSource.class); BasicDataSource dbcpDataSource = DataSourceUnwrapper.unwrap(dataSource, BasicDataSourceMXBean.class,
BasicDataSource.class);
if (dbcpDataSource != null) { if (dbcpDataSource != null) {
return new CommonsDbcp2DataSourcePoolMetadata(dbcpDataSource); return new CommonsDbcp2DataSourcePoolMetadata(dbcpDataSource);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -43,35 +43,52 @@ public final class DataSourceUnwrapper {
/** /**
* Return an object that implements the given {@code target} type, unwrapping delegate * Return an object that implements the given {@code target} type, unwrapping delegate
* or proxy if necessary. * or proxy if necessary using the specified {@code unwrapInterface}.
* @param dataSource the datasource to handle * @param dataSource the datasource to handle
* @param unwrapInterface the interface that the target type must implement
* @param target the type that the result must implement * @param target the type that the result must implement
* @param <I> the interface that the target type must implement
* @param <T> the target type * @param <T> the target type
* @return an object that implements the target type or {@code null} * @return an object that implements the target type or {@code null}
* @see Wrapper#unwrap(Class)
*/ */
public static <T> T unwrap(DataSource dataSource, Class<T> target) { public static <I, T extends I> T unwrap(DataSource dataSource, Class<I> unwrapInterface, Class<T> target) {
if (target.isInstance(dataSource)) { if (target.isInstance(dataSource)) {
return target.cast(dataSource); return target.cast(dataSource);
} }
T unwrapped = safeUnwrap(dataSource, target); I unwrapped = safeUnwrap(dataSource, unwrapInterface);
if (unwrapped != null) { if (unwrapped != null && unwrapInterface.isAssignableFrom(target)) {
return unwrapped; return target.cast(unwrapped);
} }
if (DELEGATING_DATA_SOURCE_PRESENT) { if (DELEGATING_DATA_SOURCE_PRESENT) {
DataSource targetDataSource = DelegatingDataSourceUnwrapper.getTargetDataSource(dataSource); DataSource targetDataSource = DelegatingDataSourceUnwrapper.getTargetDataSource(dataSource);
if (targetDataSource != null) { if (targetDataSource != null) {
return unwrap(targetDataSource, target); return unwrap(targetDataSource, unwrapInterface, target);
} }
} }
if (AopUtils.isAopProxy(dataSource)) { if (AopUtils.isAopProxy(dataSource)) {
Object proxyTarget = AopProxyUtils.getSingletonTarget(dataSource); Object proxyTarget = AopProxyUtils.getSingletonTarget(dataSource);
if (proxyTarget instanceof DataSource) { if (proxyTarget instanceof DataSource) {
return unwrap((DataSource) proxyTarget, target); return unwrap((DataSource) proxyTarget, unwrapInterface, target);
} }
} }
return null; return null;
} }
/**
* Return an object that implements the given {@code target} type, unwrapping delegate
* or proxy if necessary. Consider using {@link #unwrap(DataSource, Class, Class)} as
* {@link Wrapper#unwrap(Class) unwrapping} won't be considered if {@code target} is
* not an interface.
* @param dataSource the datasource to handle
* @param target the type that the result must implement
* @param <T> the target type
* @return an object that implements the target type or {@code null}
*/
public static <T> T unwrap(DataSource dataSource, Class<T> target) {
return unwrap(dataSource, target, target);
}
private static <S> S safeUnwrap(Wrapper wrapper, Class<S> target) { private static <S> S safeUnwrap(Wrapper wrapper, Class<S> target) {
try { try {
if (target.isInterface() && wrapper.isWrapperFor(target)) { if (target.isInterface() && wrapper.isWrapperFor(target)) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,8 +18,10 @@ package org.springframework.boot.jdbc;
import javax.sql.DataSource; import javax.sql.DataSource;
import com.zaxxer.hikari.HikariConfigMXBean;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import org.apache.tomcat.jdbc.pool.DataSourceProxy; import org.apache.tomcat.jdbc.pool.DataSourceProxy;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.framework.ProxyFactory;
@ -39,14 +41,16 @@ class DataSourceUnwrapperNoSpringJdbcTests {
void unwrapWithProxy() { void unwrapWithProxy() {
DataSource dataSource = new HikariDataSource(); DataSource dataSource = new HikariDataSource();
DataSource actual = wrapInProxy(wrapInProxy(dataSource)); DataSource actual = wrapInProxy(wrapInProxy(dataSource));
assertThat(DataSourceUnwrapper.unwrap(actual, HikariDataSource.class)).isSameAs(dataSource); assertThat(DataSourceUnwrapper.unwrap(actual, HikariConfigMXBean.class, HikariDataSource.class))
.isSameAs(dataSource);
} }
@Test @Test
void unwrapDataSourceProxy() { void unwrapDataSourceProxy() {
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource(); org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
DataSource actual = wrapInProxy(wrapInProxy(dataSource)); DataSource actual = wrapInProxy(wrapInProxy(dataSource));
assertThat(DataSourceUnwrapper.unwrap(actual, DataSourceProxy.class)).isSameAs(dataSource); assertThat(DataSourceUnwrapper.unwrap(actual, PoolConfiguration.class, DataSourceProxy.class))
.isSameAs(dataSource);
} }
private DataSource wrapInProxy(DataSource dataSource) { private DataSource wrapInProxy(DataSource dataSource) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,13 +21,16 @@ import java.util.function.Consumer;
import javax.sql.DataSource; import javax.sql.DataSource;
import com.zaxxer.hikari.HikariConfigMXBean;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import org.apache.tomcat.jdbc.pool.DataSourceProxy; import org.apache.tomcat.jdbc.pool.DataSourceProxy;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.framework.ProxyFactory;
import org.springframework.jdbc.datasource.DelegatingDataSource; import org.springframework.jdbc.datasource.DelegatingDataSource;
import org.springframework.jdbc.datasource.SingleConnectionDataSource; import org.springframework.jdbc.datasource.SingleConnectionDataSource;
import org.springframework.jdbc.datasource.SmartDataSource;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -44,52 +47,59 @@ class DataSourceUnwrapperTests {
@Test @Test
void unwrapWithTarget() { void unwrapWithTarget() {
DataSource dataSource = new HikariDataSource(); DataSource dataSource = new HikariDataSource();
assertThat(DataSourceUnwrapper.unwrap(dataSource, HikariDataSource.class)).isSameAs(dataSource); assertThat(DataSourceUnwrapper.unwrap(dataSource, HikariConfigMXBean.class, HikariDataSource.class))
.isSameAs(dataSource);
} }
@Test @Test
void unwrapWithWrongTarget() { void unwrapWithWrongTarget() {
DataSource dataSource = new HikariDataSource(); DataSource dataSource = new HikariDataSource();
assertThat(DataSourceUnwrapper.unwrap(dataSource, SingleConnectionDataSource.class)).isNull(); assertThat(DataSourceUnwrapper.unwrap(dataSource, SmartDataSource.class, SingleConnectionDataSource.class))
.isNull();
} }
@Test @Test
void unwrapWithDelegate() { void unwrapWithDelegate() {
DataSource dataSource = new HikariDataSource(); DataSource dataSource = new HikariDataSource();
DataSource actual = wrapInDelegate(wrapInDelegate(dataSource)); DataSource actual = wrapInDelegate(wrapInDelegate(dataSource));
assertThat(DataSourceUnwrapper.unwrap(actual, HikariDataSource.class)).isSameAs(dataSource); assertThat(DataSourceUnwrapper.unwrap(actual, HikariConfigMXBean.class, HikariDataSource.class))
.isSameAs(dataSource);
} }
@Test @Test
void unwrapWithProxy() { void unwrapWithProxy() {
DataSource dataSource = new HikariDataSource(); DataSource dataSource = new HikariDataSource();
DataSource actual = wrapInProxy(wrapInProxy(dataSource)); DataSource actual = wrapInProxy(wrapInProxy(dataSource));
assertThat(DataSourceUnwrapper.unwrap(actual, HikariDataSource.class)).isSameAs(dataSource); assertThat(DataSourceUnwrapper.unwrap(actual, HikariConfigMXBean.class, HikariDataSource.class))
.isSameAs(dataSource);
} }
@Test @Test
void unwrapWithProxyAndDelegate() { void unwrapWithProxyAndDelegate() {
DataSource dataSource = new HikariDataSource(); DataSource dataSource = new HikariDataSource();
DataSource actual = wrapInProxy(wrapInDelegate(dataSource)); DataSource actual = wrapInProxy(wrapInDelegate(dataSource));
assertThat(DataSourceUnwrapper.unwrap(actual, HikariDataSource.class)).isSameAs(dataSource); assertThat(DataSourceUnwrapper.unwrap(actual, HikariConfigMXBean.class, HikariDataSource.class))
.isSameAs(dataSource);
} }
@Test @Test
void unwrapWithSeveralLevelOfWrapping() { void unwrapWithSeveralLevelOfWrapping() {
DataSource dataSource = new HikariDataSource(); DataSource dataSource = new HikariDataSource();
DataSource actual = wrapInProxy(wrapInDelegate(wrapInDelegate(wrapInProxy(wrapInDelegate(dataSource))))); DataSource actual = wrapInProxy(wrapInDelegate(wrapInDelegate(wrapInProxy(wrapInDelegate(dataSource)))));
assertThat(DataSourceUnwrapper.unwrap(actual, HikariDataSource.class)).isSameAs(dataSource); assertThat(DataSourceUnwrapper.unwrap(actual, HikariConfigMXBean.class, HikariDataSource.class))
.isSameAs(dataSource);
} }
@Test @Test
void unwrapDataSourceProxy() { void unwrapDataSourceProxy() {
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource(); org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
DataSource actual = wrapInDelegate(wrapInProxy(dataSource)); DataSource actual = wrapInDelegate(wrapInProxy(dataSource));
assertThat(DataSourceUnwrapper.unwrap(actual, DataSourceProxy.class)).isSameAs(dataSource); assertThat(DataSourceUnwrapper.unwrap(actual, PoolConfiguration.class, DataSourceProxy.class))
.isSameAs(dataSource);
} }
@Test @Test
void unwrappingIsNotAttemptedWhenTargetIsNotAnInterface() throws SQLException { void unwrappingIsNotAttemptedWhenTargetIsNotAnInterface() {
DataSource dataSource = mock(DataSource.class); DataSource dataSource = mock(DataSource.class);
assertThat(DataSourceUnwrapper.unwrap(dataSource, HikariDataSource.class)).isNull(); assertThat(DataSourceUnwrapper.unwrap(dataSource, HikariDataSource.class)).isNull();
verifyNoMoreInteractions(dataSource); verifyNoMoreInteractions(dataSource);

Loading…
Cancel
Save