Commit b4cda625 authored by Andy Wilkinson's avatar Andy Wilkinson

Break cycle caused by JndiDataSourceAutoConfiguration

There's a long cycle when Spring Data REST, Data JPA and Actuator
are used in an app that retrieves its DataSource from JNDI. The cycle
is:

- WebMvcAutoConfiguration
- HttpMessageConverters
- MappingJackson2HttpMessageConverter (needs an ObjectMapper)
- SpringBootRepositoryRestMvcConfiguration
- ObjectMapper
- RepositoryResourceMappings (part of a custom Jackson module)
- Repositories
- EntityManagerFactory (Triggered by application's Spring Data JPA repository)
- HibernateJpaAutoConfiguration
- JndiDataSourceAutoConfiguration
- MBeanExporter (Used to prevent export of DataSource MBean that's already in JMX)
- EndpointMBeanExportAutoConfiguration
- ObjectMapper (Used to format JSON produced by the exported endpoints)

Spring Data Rest caused the ObjectMapper to depend on JPA. JPA depends
on the DataSource. JnidDataSourceAutoConfiguration depends on the
MBeanExporter. Actuator's MBeanExporter requires an ObjectMapper to
produce JSON strings.

This commit breaks the cycle by making JndiDataSourceAutoConfiguration
access the MBeanExporter lazily. Rather than using `@Lazy`. which does
not work with `@Autowired(required=false)`, the application context
is injected and the MBeanExporter is retrieved manually when it is
needed.

Closes gh-4980
parent d05f9417
......@@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.jdbc;
import javax.sql.DataSource;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
......@@ -25,6 +26,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.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
......@@ -48,8 +50,8 @@ import org.springframework.jmx.support.JmxUtils;
@EnableConfigurationProperties(DataSourceProperties.class)
public class JndiDataSourceAutoConfiguration {
@Autowired(required = false)
private MBeanExporter mbeanExporter;
@Autowired
private ApplicationContext context;
@Bean(destroyMethod = "")
@ConditionalOnMissingBean
......@@ -61,8 +63,14 @@ public class JndiDataSourceAutoConfiguration {
}
private void excludeMBeanIfNecessary(Object candidate, String beanName) {
if (this.mbeanExporter != null && JmxUtils.isMBean(candidate.getClass())) {
this.mbeanExporter.addExcludedBean(beanName);
try {
MBeanExporter mbeanExporter = this.context.getBean(MBeanExporter.class);
if (JmxUtils.isMBean(candidate.getClass())) {
mbeanExporter.addExcludedBean(beanName);
}
}
catch (NoSuchBeanDefinitionException ex) {
// No exporter. Exclusion is unnecessary
}
}
......
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