记录一次使用淘宝连接池com.alibaba.druid.stat.DruidDataSourceStatManager产生的错误
druid
使用时很方便,提供了强大的监控和扩展功能。
错误产生场景:单台Tomcat部署多个 springboot 构建的项目,并且多个项目都使用driud连接池,单独启动其中任何一个都没有问题。同时启动时就会报错
org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [com.alibaba.druid.filter.stat.StatFilter@36ee5032] with key 'statFilter'; nested exception is javax.ma
nagement.InstanceAlreadyExistsException: com.alibaba.druid.filter.stat:name=statFilter,type=StatFilter at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:625)
at org.springframework.jmx.export.MBeanExporter.lambda$registerBeans$2(MBeanExporter.java:551)
at java.util.HashMap.forEach(HashMap.java:1288)
at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:551)
at org.springframework.jmx.export.MBeanExporter.afterSingletonsInstantiated(MBeanExporter.java:434)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:777)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:869)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:395)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:327)
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:155)
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:135)
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:87)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:172)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5178)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:752)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:728)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:734)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1107)
at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1841)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.management.InstanceAlreadyExistsException: com.alibaba.druid.filter.stat:name=statFilter,type=StatFilter
at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324)
at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522)
at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:137)
at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:671)
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:615)
... 27 common frames omitted
上边错误总结起来就是:
Caused by: javax.management.InstanceAlreadyExistsException: com.alibaba.druid.filter.stat:name=statFilter,type=StatFilter
出现这种问题是因为同时部署的时候spring 默认的mbean名字都一样了,解决问题只需要在每个yml下配置spring.jmx.default-domain= 自定义名字
,名字不同,实例化出的对象就不一样了。
后来找到了druid的源码,也有人在GitHub提问同样的问题。
https://github.com/alibaba/druid/issues?q=InstanceAlreadyExistsException
还有大神提供了另外的解决方案把spring的自动探测关闭,应用还没有到全局复用对象的时候,即便使用也估计是使用RPC框架,以下是关闭jmx自动探测的spring配置
<bean class="org.springframework.jmx.export.MBeanExporter">
<property name="autodetectModeName">
<value>AUTODETECT_NONE</value>
</property>
</bean>
Spring提供了4个取值: AUTODETECT_NONE 不启用自动探测,需要手动向MBean Server进行注册,即通过MBeanExporter的beans属性进入注册; AUTODETECT_MBEAN 在当前IOC容器中进行查找MBean组件; AUTODETECT_ASSEMBLER 设置根据MBeanInfoAssembler的策略进行探测; AUTODETECT_ALL 自动探测,是AUTODETECT_MBEAN和AUTODETECT_ASSEMBLER的并集。