Search code examples
spring-bootspring-jmx

SpringBoot : Setting DataSource "jmx-enabled" is not registering the Datasource


I am trying to add my data source to JMX by setting the property "jmx-enabled" to true. I have two data sources, therefore the configuration properties are a little different:

datasource:
  main:
    driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
    url: jdbc:sqlserver://chico-testdb1.build.internal\CHICOTEST;selectMethod=cursor;applicationName=omc;sendStringParametersAsUnicode=false
    username: *
    password: *
    max-active: 150
    jmx-enabled: true

I looked at the DataSourceAutoConfiguration class and it appears to only create the MBean when the configuration uses the "spring.datasource" prefix. So I modeled my own configuration after this example:

    @Bean
    @ConditionalOnProperty(prefix = "datasource.main", name = "jmx-enabled", havingValue="true")
    public Object dataSourceMBean(@Qualifier("mainDataSource") DataSource dataSource) {
        if (dataSource instanceof DataSourceProxy) {
            try {
                return ((DataSourceProxy) dataSource).createPool().getJmxPool();
            }
            catch (SQLException ex) {
                logger.warn("Cannot expose DataSource to JMX (could not connect)");
            }
        }
        return null;
    }

The condition is working perfectly and this method is returning the Jmx connection pool. However, this bean is still not getting registered with the MBeanServer and I am seeing no exceptions in the logs.

I have been able to work around this by explicitly registering the bean with the server but this but I feel like there should be a better way?

    @Bean
    @ConditionalOnProperty(prefix = "datasource.main", name = "jmx-enabled", havingValue="true")
    public ConnectionPool getJmxPool(@Qualifier("mainDataSource") DataSource dataSource, MBeanServer mBeanServer) throws SQLException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException, MalformedObjectNameException {
        if (dataSource instanceof DataSourceProxy) {
            ConnectionPool pool = ((DataSourceProxy)dataSource).createPool().getJmxPool();
            mBeanServer.registerMBean(pool, new ObjectName("com.build.jdbc:type="+ dataSource.getClass().getName()+",name=main"));
            return pool;
        }
        return null;
    }

Solution

  • Using an inner static class and explicitly depending on the mbeanExporter resolves the issue when using spring-boot 1.3.2.RELEASE

    @Configuration
    @ConditionalOnProperty(prefix = "datasource.main", name = "jmx-enabled")
    @ConditionalOnClass(DataSourceProxy.class)
    @ConditionalOnMissingBean(name = "mainDataSourceMBean")
    protected static class TomcatDataSourceJmxConfiguration {
    
        @Bean
        @DependsOn("mbeanExporter")
        public Object mainDataSourceMBean(@Qualifier("mainDataSource") DataSource dataSource) {
            if (dataSource instanceof DataSourceProxy) {
                try {
                    return ((DataSourceProxy) dataSource).createPool().getJmxPool();
                } catch (SQLException ex) {
                    logger.warn("Cannot expose DataSource to JMX (could not connect)");
                }
            }
            return null;
        }
    }