聊聊Druid register mbean error的問題
key: [com.alibaba.druid.stat.DruidDataSourceStatManager.addDataSource(DruidDataSourceStatManager.java:154)] register mbean error
在使用數據庫連接池時(本文通用於其他使用jmx mbean的應用),運行幾天後出現如下錯誤
2014/11/18 10:31:00,617 [ERROR] [localhost-startStop-6] [com.alibaba.druid.stat.DruidDataSourceStatManager.addDataSource(DruidDataSourceStatManager.java:154)] register mbean error
javax.management.InstanceAlreadyExistsException: com.alibaba.druid:type=DruidDataSource,id=Druid MySQL DB pool
at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:453)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.internal_addObject(DefaultMBeanServerInterceptor.java:1484)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:963)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:917)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:312)
at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:482)
at com.alibaba.druid.stat.DruidDataSourceStatManager.addDataSource(DruidDataSourceStatManager.java:152)
at com.alibaba.druid.pool.DruidDataSource$1.run(DruidDataSource.java:1298)
at java.security.AccessController.doPrivileged(Native Method)
at com.alibaba.druid.pool.DruidDataSource.registerMbean(DruidDataSource.java:1294)
at com.alibaba.druid.pool.DruidDataSource.init(DruidDataSource.java:623)
at com.longdai.data.ConnectionManagerDruid.<init>(ConnectionManagerDruid.java:68)
at com.longdai.data.ConnectionManager.getInstance(ConnectionManager.java:86)
at com.longdai.data.dao.Database.<clinit>(Database.java:22)
at com.longdai.service.admin.CloseNetWorkService.getNetWorkById(CloseNetWorkService.java:87)
at com.longdai.service.admin.CloseNetWorkService$$FastClassByCGLIB$$bbdb465c.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:700)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at com.gozap.services.ServiceMethodInterceptor.invoke(ServiceMethodInterceptor.java:31)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)
at com.longdai.service.admin.CloseNetWorkService$$EnhancerByCGLIB$$19cbebaf.getNetWorkById(<generated>)
at com.longdai.system.listener.CloseNetWorkConfigiListener.contextInitialized(CloseNetWorkConfigiListener.java:37)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4791)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5285)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:618)
at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:963)
at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1600)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
查看源碼,一直跟蹤到
at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:453)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.internal_addObject(DefaultMBeanServerInterceptor.java:1484) // 這裡
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:963)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:917)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:312) //這裡入口
一路跟蹤源碼,傳入的參數一直是name屬性,查看上層 DruidDataSourceStatManager.java addDataSource(Object dataSource, String name)
在看上層: DruidDataSource.java line:1298
這裡傳入瞭數據源的name屬性,經過上面的分析,是利用DataSource的name屬性拼接成一個id,然後用次id註冊mbean, 然而,druid的name屬性寫成瞭一個默認值
故此註冊失敗。
現在知道瞭原因,為什麼運行幾天後才出現這個錯誤,並且運維說有回滾到瞭上個版本,在部署(直接重新部署,並沒有重啟tomcat/jvm)的時候就直接報這個錯誤,經過上面的推斷是jvm中已經有一個此id的mbean瞭,故此即使重新部署還是失敗,我給想瞭個辦法,重啟tomcat,搞定,果然奏效。
在來看看druid的wiki中,雖然提示瞭配置name屬性,但是在配置文件中配置後是不起作用的,經過查看源碼發現並沒有加載次屬性,所以配置瞭沒用,後來我在代碼中獲取配置文件的name屬性,然後dataSource.setName(name),雖然名字設置成功瞭,在druid的監控頁面也可以看的自定義的名字,但是不幸的是druid運行幾天出錯瞭或者重新部署,然後重新向jvm註冊mbean,導致瞭出錯。
再來看看datasource的name的默認值是怎麼設置的DruidAbstractDataSource.java line: 849
可以看到在getName屬性中是DataSource-加上計算的一個hash值,但是此方法隻在getName時返回,而在註冊mbean時druid的name默認是null, 在註冊mbean時分析下面的代碼DruidDataSourceStatManager.java line: 161
代碼顯示是根據dataSource計算出來莪一個hash值,然後進行註冊mbean。
經過上面的分析在註冊mbean時,一定要保證registerMBean的name參數唯一,還要在上層攔截異常
InstanceAlreadyExistsException,然後自動處理異常
總結:在使用Druid的時候,不要使用name屬性,druid官網並沒有給出說明,本文在此給大傢一個解釋和處理方法。另外1.0.5版本配置後是不起作用的,需要自己強行setName。如自己配置瞭name,為防止出錯,最好修改Druid源碼 DruidDataSourceStatManager.java addDataSource(Object dataSource, String name) ,在生成objectName是在加一個 hash(參考161)。另外大傢在註冊MBean時,一定要保證id的唯一,以及重復的處理方式。如果出現瞭這個錯誤,就將與本項目使用的同一個jvm的項目都關掉,清理掉本jvm,然後重啟服務
附: https://github.com/alibaba/druid
到此這篇關於聊聊Druid register mbean error的問題的文章就介紹到這瞭,更多相關Druid register mbean error內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 記錄一次connection reset 錯誤的解決全過程
- 解決springboot的findOne方法沒有合適的參數使用問題
- 詳解SpringBoot自定義配置與整合Druid
- SpringBoot集成Druid連接池連接MySQL8.0.11
- 解決Spring JPA 使用@transaction註解時產生CGLIB代理沖突問題