Не удалось отменить регистрацию DataSource JMX MBean при отключении приложения загрузки Spring

У меня есть простое приложение загрузки Spring, используя org.apache.commons.dbcp2.BasicDataSource как dataSource bean.

Источник данных автоматически отображается как MBean с помощью Spring загрузки.

Объявление bean:

@Bean
public DataSource dataSource() {
    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setUrl(dbUrl);
    dataSource.setDriverClassName(jdbcDriver);
    dataSource.setUsername(dbUserName);
    dataSource.setPassword(dbPassword);
    return dataSource;
}

Все работает отлично. Однако при закрытии приложения я вижу ошибку. Эта ошибка возникает только при запуске исполняемой банки. При использовании плагина Gradle Spring (gradle bootRun) это не отображается.

javax.management.InstanceNotFoundException: org.apache.commons.dbcp2:name=dataSource,type=BasicDataSource
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.getMBean(DefaultMBeanServerInterceptor.java:1095)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.exclusiveUnregisterMBean(DefaultMBeanServerInterceptor.java:427)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.unregisterMBean(DefaultMBeanServerInterceptor.java:415)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.unregisterMBean(JmxMBeanServer.java:546)
    at org.apache.commons.dbcp2.BasicDataSource.close(BasicDataSource.java:1822)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.springframework.beans.factory.support.DisposableBeanAdapter.invokeCustomDestroyMethod(DisposableBeanAdapter.java:350)
    at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:273)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:540)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:516)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:827)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:485)
    at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:921)
    at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:895)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.doClose(EmbeddedWebApplicationContext.java:152)
    at org.springframework.context.support.AbstractApplicationContext$1.run(AbstractApplicationContext.java:809)

Мне интересно, 1. Как этот bean открывается как JMX MBean? 2. Как правильно отменить регистрацию этого MBean?

Ответы

Ответ 1

Spring пытается закрыть BasicDataSource дважды:

  • BasicDataSource автоматически закрывается при закрытии приложения
  • Spring использовать метод уничтожения по умолчанию, чтобы закрыть DataSource, но он уже закрыт

Чтобы этого избежать, используйте:

@Bean(destroyMethod = "")
public DataSource dataSource() 

В конфигурации Java

Ответ 2

Попробуйте использовать spring SimpleDriverDataSource вместо BasicDataSource. Это может помочь.

Ответ 3

Я столкнулся с той же проблемой. Добавление сервера MBean и регистрация источника данных также не могут его исправить.

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jmx.html

Мое заключение заключается в том, что DBCP2 BasicDataSource имеет ошибку при незарегистрировании себя с сервера MBean.

Я исправил шахту, переключившись на mchange c3p0: http://www.mchange.com/projects/c3p0/

Ответ 4

У меня была такая же проблема. c3p0 работает очень хорошо.

при использовании spring framework - pom.xml

<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
   <groupId>com.mchange</groupId>
   <artifactId>c3p0</artifactId>
   <version>0.9.5.2</version>
</dependency>

изначально использовался

DataSource ds_unpooled = DataSources.unpooledDataSource(persistenceUrl,
            persistenceUsername,
            persistencePassword);
return DataSources.pooledDataSource(ds_unpooled);

но он не смог обработать нагрузку, которую мне нужно выполнить, и переключился на следующий

ComboPooledDataSource cpds = new ComboPooledDataSource();
    cpds.setDriverClass( persistenceDriver ); //loads the jdbc driver
    cpds.setJdbcUrl( persistenceUrl );
    cpds.setUser(persistenceUsername);
    cpds.setPassword(persistencePassword);
    cpds.setMinPoolSize(5);
    cpds.setMaxPoolSize(50);
    cpds.setUnreturnedConnectionTimeout(1800);
    cpds.setMaxStatements(50);
    cpds.setMaxIdleTime(21600);
    cpds.setIdleConnectionTestPeriod(10800);
return cpds;

эти значения взяты из других сообщений, которые я собрал в Интернете.

в моем опыте для моей конкретной задачи, запуск c3p0 выполняется быстрее, чем dbcp2 v: 2.1.1 в той же среде.

надеюсь, что эта помощь немного. ура!

Ответ 5

BasicDataSource extends BasicDataSourceMXBean, поэтому он автоматически зарегистрирован на сервере JMX как MBean [org.apache.commons.dbcp2:name=dataSource,type=BasicDataSource]. Когда выключение Springboot, MBeanExporter отменяет регистрацию MBean, тогда springboot пытается уничтожить BasicDataSource и вызывает метод BasicDataSources close(), снова отменяет MBean (BasicDataSource ловит JMException и печатает это предупреждение). Это просто предупреждение. Если вы не хотите его печатать, вы можете отключить JMX в Springboot.

application.yml
spring:
jmx:
enabled: false