diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfiguration.java index 8dfe8079c74..f929826830f 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.jdbc; import javax.sql.DataSource; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -28,12 +29,15 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; +import org.springframework.jmx.export.MBeanExporter; +import org.springframework.jmx.support.JmxUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for a JNDI located * {@link DataSource}. * * @author Phillip Webb + * @author Andy Wilkinson * @since 1.2.0 */ @Configuration @@ -44,11 +48,22 @@ import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; @EnableConfigurationProperties(DataSourceProperties.class) public class JndiDataSourceAutoConfiguration { + @Autowired(required = false) + private MBeanExporter mbeanExporter; + @Bean(destroyMethod = "") @ConditionalOnMissingBean public DataSource dataSource(DataSourceProperties properties) { JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup(); - return dataSourceLookup.getDataSource(properties.getJndiName()); + DataSource dataSource = dataSourceLookup.getDataSource(properties.getJndiName()); + excludeMBeanIfNecessary(dataSource, "dataSource"); + return dataSource; + } + + private void excludeMBeanIfNecessary(Object candidate, String beanName) { + if (this.mbeanExporter != null && JmxUtils.isMBean(candidate.getClass())) { + this.mbeanExporter.addExcludedBean(beanName); + } } } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfigurationTests.java new file mode 100644 index 00000000000..30ada4b97c0 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JndiDataSourceAutoConfigurationTests.java @@ -0,0 +1,133 @@ +/* + * Copyright 2012-2015 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.Set; + +import javax.naming.NamingException; +import javax.sql.DataSource; + +import org.apache.commons.dbcp2.BasicDataSource; +import org.junit.After; +import org.junit.Test; +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.boot.test.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.jmx.export.MBeanExporter; +import org.springframework.mock.jndi.SimpleNamingContextBuilder; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.hasSize; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +/** + * Tests for {@link JndiDataSourceAutoConfiguration} + * + * @author Andy Wilkinson + */ +public class JndiDataSourceAutoConfigurationTests { + + private AnnotationConfigApplicationContext context; + + private SimpleNamingContextBuilder jndi; + + @After + public void cleanup() { + if (this.jndi != null) { + this.jndi.clear(); + } + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void dataSourceIsAvailableFromJndi() throws IllegalStateException, + NamingException { + DataSource dataSource = new BasicDataSource(); + this.jndi = configureJndi("foo", dataSource); + + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, + "spring.datasource.jndi-name:foo"); + this.context.register(JndiDataSourceAutoConfiguration.class); + this.context.refresh(); + + assertEquals(dataSource, this.context.getBean(DataSource.class)); + } + + @SuppressWarnings("unchecked") + @Test + public void mbeanDataSourceIsExcludedFromExport() throws IllegalStateException, + NamingException { + DataSource dataSource = new BasicDataSource(); + this.jndi = configureJndi("foo", dataSource); + + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, + "spring.datasource.jndi-name:foo"); + this.context.register(JndiDataSourceAutoConfiguration.class, + MBeanExporterConfiguration.class); + this.context.refresh(); + + assertEquals(dataSource, this.context.getBean(DataSource.class)); + MBeanExporter exporter = this.context.getBean(MBeanExporter.class); + Set excludedBeans = (Set) new DirectFieldAccessor(exporter) + .getPropertyValue("excludedBeans"); + assertThat(excludedBeans, contains("dataSource")); + } + + @SuppressWarnings("unchecked") + @Test + public void standardDataSourceIsNotExcludedFromExport() throws IllegalStateException, + NamingException { + DataSource dataSource = new org.apache.commons.dbcp.BasicDataSource(); + this.jndi = configureJndi("foo", dataSource); + + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, + "spring.datasource.jndi-name:foo"); + this.context.register(JndiDataSourceAutoConfiguration.class, + MBeanExporterConfiguration.class); + this.context.refresh(); + + assertEquals(dataSource, this.context.getBean(DataSource.class)); + MBeanExporter exporter = this.context.getBean(MBeanExporter.class); + Set excludedBeans = (Set) new DirectFieldAccessor(exporter) + .getPropertyValue("excludedBeans"); + assertThat(excludedBeans, hasSize(0)); + } + + private SimpleNamingContextBuilder configureJndi(String name, DataSource dataSource) + throws IllegalStateException, NamingException { + SimpleNamingContextBuilder builder = SimpleNamingContextBuilder + .emptyActivatedContextBuilder(); + builder.bind(name, dataSource); + return builder; + } + + private static class MBeanExporterConfiguration { + + @Bean + MBeanExporter mbeanExporter() { + return new MBeanExporter(); + } + } + +}