我有一个简单的Spring Boot应用程序,使用org.apache.commons.dbcp2.BasicDataSource作为dataSource bean。
数据源通过Spring引导自动公开为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?
Spring试图关闭BasicDataSource两次:
- BasicDataSource关闭自己当应用程序关闭
- Spring使用默认的destroy方法来关闭数据源,但是它已经关闭了
要避免这种情况,请使用:
@Bean(destroyMethod = "")
public DataSource dataSource()
在您的Java配置
我遇到了同样的问题。添加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/
BasicDataSource extends BasicDataSourceMXBean
,因此在JMX服务器上自动注册为MBean [org.apache.commons.dbcp2:name=dataSource,type=BasicDataSource]
。当springboot关闭时,mbean出口商注销MBean,然后springboot尝试销毁BasicDataSource
,并调用BasicDataSource的方法close()
,再次注销MBean (BasicDataSource捕获JMException,并打印此警告)。这只是一个警告。如果不想打印它,可以在springboot中禁用JMX。
application.yml
spring:
jmx:
enabled: false
我也有同样的问题。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执行得快。希望这对你有帮助。干杯!