Commit 03b43225 authored by Stephane Nicoll's avatar Stephane Nicoll

Allow Hikari to export MBeans on the auto-configured datasource

This commit makes sure that if the `register-mbeans` property of the
Hikary datasource config is set, Spring Boot doesn't attempt to expose
the mbean again.

Closes gh-5114
parent e4c4251f
...@@ -106,7 +106,8 @@ public class DataSourceAutoConfiguration { ...@@ -106,7 +106,8 @@ public class DataSourceAutoConfiguration {
@Conditional(PooledDataSourceCondition.class) @Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class, @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class }) DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration { protected static class PooledDataSourceConfiguration {
} }
......
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.jdbc;
import javax.annotation.PostConstruct;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.context.annotation.Configuration;
import org.springframework.jmx.export.MBeanExporter;
/**
* Configures DataSource related MBeans.
*
* @author Stephane Nicoll
*/
@Configuration
@ConditionalOnProperty(prefix = "spring.jmx", name = "enabled", havingValue = "true", matchIfMissing = true)
class DataSourceJmxConfiguration {
@Configuration
@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnSingleCandidate(HikariDataSource.class)
static class Hikari {
private final HikariDataSource dataSource;
private final ObjectProvider<MBeanExporter> mBeanExporter;
Hikari(HikariDataSource dataSource,
ObjectProvider<MBeanExporter> mBeanExporter) {
this.dataSource = dataSource;
this.mBeanExporter = mBeanExporter;
}
@PostConstruct
public void validateMBeans() {
MBeanExporter exporter = this.mBeanExporter.getIfUnique();
if (exporter != null && this.dataSource.isRegisterMbeans()) {
exporter.addExcludedBean("dataSource");
}
}
}
}
/*
* Copyright 2012-2017 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.lang.management.ManagementFactory;
import java.util.UUID;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import com.zaxxer.hikari.HikariDataSource;
import org.hsqldb.jdbc.JDBCDriver;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jmx.export.UnableToRegisterMBeanException;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DataSourceJmxConfiguration}.
*
* @author Stephane Nicoll
*/
public class DataSourceJmxConfigurationTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
private ConfigurableApplicationContext context;
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void hikariCustomCannotUseRegisterMBeansByDefault() {
this.thrown.expect(UnableToRegisterMBeanException.class);
this.thrown.expectMessage("myDataSource");
load(CustomHikariConfiguration.class);
}
@Test
public void hikariAutoConfiguredCanUseRegisterMBeans()
throws MalformedObjectNameException {
String poolName = UUID.randomUUID().toString();
load("spring.datasource.type=" + HikariDataSource.class.getName(),
"spring.datasource.hikari.pool-name=" + poolName,
"spring.datasource.hikari.register-mbeans=true");
assertThat(this.context.getBeansOfType(HikariDataSource.class)).hasSize(1);
assertThat(this.context.getBean(HikariDataSource.class).isRegisterMbeans())
.isTrue();
MBeanServer mBeanServer = this.context.getBean(MBeanServer.class);
validateHikariMBeansRegistration(mBeanServer, poolName, true);
}
@Test
public void hikariAutoConfiguredUsesJmsFlag() throws MalformedObjectNameException {
String poolName = UUID.randomUUID().toString();
load("spring.datasource.type=" + HikariDataSource.class.getName(),
"spring.jmx.enabled=false",
"spring.datasource.hikari.pool-name=" + poolName,
"spring.datasource.hikari.register-mbeans=true");
assertThat(this.context.getBeansOfType(HikariDataSource.class)).hasSize(1);
assertThat(this.context.getBean(HikariDataSource.class).isRegisterMbeans())
.isTrue();
// Hikari can still register mBeans
validateHikariMBeansRegistration(ManagementFactory.getPlatformMBeanServer(),
poolName, true);
}
private void validateHikariMBeansRegistration(MBeanServer mBeanServer,
String poolName, boolean expected) throws MalformedObjectNameException {
assertThat(mBeanServer.isRegistered(new ObjectName(
"com.zaxxer.hikari:type=Pool (" + poolName + ")"))).isEqualTo(expected);
assertThat(mBeanServer.isRegistered(new ObjectName(
"com.zaxxer.hikari:type=PoolConfig (" + poolName + ")"))).isEqualTo(expected);
}
private void load(String... environment) {
load(null, environment);
}
private void load(Class<?> config, String... environment) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
String jdbcUrl = "jdbc:hsqldb:mem:test-" + UUID.randomUUID().toString();
TestPropertyValues.of(environment).and("spring.datasource.url", jdbcUrl)
.applyTo(ctx);
if (config != null) {
ctx.register(config);
}
ctx.register(JmxAutoConfiguration.class, DataSourceAutoConfiguration.class);
ctx.refresh();
this.context = ctx;
}
@Configuration
static class CustomHikariConfiguration {
@Bean
public HikariDataSource myDataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:hsqldb:mem:custom");
dataSource.setDriverClassName(JDBCDriver.class.getName());
dataSource.setRegisterMbeans(true);
return dataSource;
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment