19

我有一个使用 org.apache.commons.dbcp2.BasicDataSource 作为数据源 bean 的简单 Spring Boot 应用程序。

Spring boot 自动将数据源公开为 MBean。

bean声明:

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

一切正常。但是,我在关闭应用程序时看到错误。此错误仅在运行可执行 jar 时发生。使用 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?

4

4 回答 4

26

Spring 试图关闭 BasicDataSource 两次:

  1. BasicDataSource 在应用程序关闭时自动关闭
  2. Spring使用默认的destroy方法关闭DataSource但它已经关闭了

为避免这种情况,请使用:

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

在您的 Java 配置中

于 2017-01-30T14:31:16.893 回答
1

我遇到了同样的问题。添加 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/

于 2015-03-13T01:09:19.380 回答
1

BasicDataSource extends BasicDataSourceMXBean,因此它会自动向 JMX 服务器注册为 MBean [org.apache.commons.dbcp2:name=dataSource,type=BasicDataSource]。当 springboot 关闭时,MBeanExporter 注销 MBean,然后 springboot 尝试销毁BasicDataSource,并调用 BasicDataSource 的方法close(),再次注销 MBean(BasicDataSource 捕获 JMException,并打印此警告)。这只是一个警告。如果不想打印,可以在springboot中禁用JMX。

application.yml
spring:
jmx:
enabled: false
于 2017-02-14T15:32:42.383 回答
0

我遇到过同样的问题。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 执行得更快。

希望这会有所帮助。干杯!

于 2016-07-26T22:44:59.700 回答