diff --git a/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatManager.java b/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatManager.java index 9cc649ca12..8e6cc4e321 100644 --- a/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatManager.java +++ b/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatManager.java @@ -16,10 +16,8 @@ package com.alibaba.druid.stat; import java.lang.management.ManagementFactory; -import java.lang.reflect.Method; -import java.util.IdentityHashMap; +import java.util.HashMap; import java.util.Map; -import java.util.Properties; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; @@ -37,179 +35,124 @@ import javax.management.openmbean.TabularType; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.support.logging.Log; import com.alibaba.druid.support.logging.LogFactory; -import com.alibaba.druid.util.DruidDataSourceUtils; +import com.alibaba.druid.util.ConcurrentIdentityHashMap; import com.alibaba.druid.util.JMXUtils; -@SuppressWarnings("rawtypes") public class DruidDataSourceStatManager implements DruidDataSourceStatManagerMBean { - public final static String SYS_PROP_INSTANCES = "druid.dataSources"; + private final static Log LOG = LogFactory.getLog(DruidDataSourceStatManager.class); - private final static Log LOG = LogFactory.getLog(DruidDataSourceStatManager.class); + private final static DruidDataSourceStatManager instance = new DruidDataSourceStatManager(); - private final static DruidDataSourceStatManager instance = new DruidDataSourceStatManager(); - - private final AtomicLong resetCount = new AtomicLong(); + private final AtomicLong resetCount = new AtomicLong(); // global instances - private static IdentityHashMap dataSources; + private static final ConcurrentIdentityHashMap dataSources = new ConcurrentIdentityHashMap(); - private final static String MBEAN_NAME = "com.alibaba.druid:type=DruidDataSourceStat"; + private final static String MBEAN_NAME = "com.alibaba.druid:type=DruidDataSourceStat"; public static DruidDataSourceStatManager getInstance() { return instance; } - + public static void cear() { - IdentityHashMap dataSources = getInstances(); - - synchronized (dataSources) { - MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); - for (Object item : dataSources.entrySet()) { - Map.Entry entry = (Map.Entry) item; - ObjectName objectName = (ObjectName) entry.getValue(); - - if (objectName == null) { - continue; - } - - try { - mbeanServer.unregisterMBean(objectName); - } catch (JMException e) { - LOG.error(e.getMessage(), e); - } - } - dataSources.clear(); - } - } - - @SuppressWarnings("unchecked") - public static IdentityHashMap getInstances() { - if (dataSources == null) { - dataSources = getInstances0(); - } - - return dataSources; - } - - @SuppressWarnings("unchecked") - static IdentityHashMap getInstances0() { - Properties properties = System.getProperties(); - IdentityHashMap instances = (IdentityHashMap) properties.get(SYS_PROP_INSTANCES); - - if (instances == null) { - synchronized (properties) { - instances = (IdentityHashMap) properties.get(SYS_PROP_INSTANCES); - - if (instances == null) { - instances = new IdentityHashMap(); - properties.put(SYS_PROP_INSTANCES, instances); - } - } - } - - return instances; - } - - public synchronized static ObjectName addDataSource(Object dataSource, String name) { - final IdentityHashMap instances = getInstances(); - - synchronized (instances) { - MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); - if (instances.size() == 0) { - try { - - ObjectName objectName = new ObjectName(MBEAN_NAME); - if (!mbeanServer.isRegistered(objectName)) { - mbeanServer.registerMBean(instance, objectName); - } - } catch (JMException ex) { - LOG.error("register mbean error", ex); - } - } - - ObjectName objectName = null; - if (name != null) { - try { - objectName = new ObjectName("com.alibaba.druid:type=DruidDataSource,id=" + name); - mbeanServer.registerMBean(dataSource, objectName); - } catch (JMException ex) { - LOG.error("register mbean error", ex); - objectName = null; - } - } - + MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); + for (Map.Entry entry : dataSources.entrySet()) { + ObjectName objectName = entry.getValue(); if (objectName == null) { - try { - int id = System.identityHashCode(dataSource); - objectName = new ObjectName("com.alibaba.druid:type=DruidDataSource,id=" + id); - mbeanServer.registerMBean(dataSource, objectName); - } catch (JMException ex) { - LOG.error("register mbean error", ex); - objectName = null; - } + continue; + } + try { + mbeanServer.unregisterMBean(objectName); + } catch (JMException e) { + LOG.error(e.getMessage(), e); } - - instances.put(dataSource, objectName); - return objectName; } + dataSources.clear(); } - public synchronized static void removeDataSource(Object dataSource) { - IdentityHashMap instances = getInstances(); + public synchronized static ObjectName add(DruidDataSource dataSource, String name) { + MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); + if (dataSources.size() == 0) { + try { - synchronized (instances) { - ObjectName objectName = (ObjectName) instances.remove(dataSource); - - if (objectName == null) { - objectName = DruidDataSourceUtils.getObjectName(dataSource); - } - - if (objectName == null) { - LOG.error("unregister mbean failed. url " + DruidDataSourceUtils.getUrl(dataSource)); - return; - } - - MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); - - if (objectName != null) { - try { - mbeanServer.unregisterMBean(objectName); - } catch (JMException ex) { - LOG.error("unregister mbean error", ex); + ObjectName objectName = new ObjectName(MBEAN_NAME); + if (!mbeanServer.isRegistered(objectName)) { + mbeanServer.registerMBean(instance, objectName); } + } catch (JMException ex) { + LOG.error("register mbean error", ex); } + } - if (instances.size() == 0) { - try { - mbeanServer.unregisterMBean(new ObjectName(MBEAN_NAME)); - } catch (JMException ex) { - LOG.error("unregister mbean error", ex); - } + ObjectName objectName = null; + if (name != null) { + try { + objectName = new ObjectName("com.alibaba.druid:type=DruidDataSource,id=" + name); + mbeanServer.registerMBean(dataSource, objectName); + } catch (JMException ex) { + LOG.error("register mbean error", ex); + objectName = null; + } + } + + if (objectName == null) { + try { + int id = System.identityHashCode(dataSource); + objectName = new ObjectName("com.alibaba.druid:type=DruidDataSource,id=" + id); + mbeanServer.registerMBean(dataSource, objectName); + } catch (JMException ex) { + LOG.error("register mbean error", ex); + objectName = null; + } + } + + dataSources.put(dataSource, objectName); + return objectName; + } + + public synchronized static void remove(DruidDataSource dataSource) { + ObjectName objectName = dataSources.remove(dataSource); + + if (objectName == null) { + objectName = dataSource.getObjectName(); + } + + if (objectName == null) { + LOG.error("unregister mbean failed. url " + dataSource.getUrl()); + return; + } + + MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); + + if (objectName != null) { + try { + mbeanServer.unregisterMBean(objectName); + } catch (JMException ex) { + LOG.error("unregister mbean error", ex); + } + } + + if (dataSources.size() == 0) { + try { + mbeanServer.unregisterMBean(new ObjectName(MBEAN_NAME)); + } catch (JMException ex) { + LOG.error("unregister mbean error", ex); } } } - @SuppressWarnings("unchecked") public static Set getDruidDataSourceInstances() { return dataSources.keySet(); } public void reset() { - IdentityHashMap dataSources = getInstances(); - - synchronized (dataSources) { - for (Object item : dataSources.keySet()) { - try { - Method method = item.getClass().getMethod("resetStat"); - method.invoke(item); - } catch (Exception e) { - LOG.error("resetStat error", e); - } - } - - resetCount.incrementAndGet(); + final Set dataSources = getDruidDataSourceInstances(); + for (DruidDataSource dataSource : dataSources) { + dataSource.resetStat(); } + + resetCount.incrementAndGet(); } public long getResetCount() { @@ -223,18 +166,80 @@ public class DruidDataSourceStatManager implements DruidDataSourceStatManagerMBe TabularType tabularType = new TabularType("DruidDataSourceStat", "DruidDataSourceStat", rowType, indexNames); TabularData data = new TabularDataSupport(tabularType); - final Set dataSources = getInstances().keySet(); - for (Object dataSource : dataSources) { + final Set dataSources = getDruidDataSourceInstances(); + for (DruidDataSource dataSource : dataSources) { data.put(getCompositeData(dataSource)); } return data; } - public CompositeDataSupport getCompositeData(Object dataSource) throws JMException { + public CompositeDataSupport getCompositeData(DruidDataSource dataSource) throws JMException { CompositeType rowType = getDruidDataSourceCompositeType(); - Map map = DruidDataSourceUtils.getStatDataForMBean(dataSource); + Map map = new HashMap(); + + // 0 - 4 + map.put("Name", dataSource.getName()); + map.put("URL", dataSource.getUrl()); + map.put("CreateCount", dataSource.getCreateCount()); + map.put("DestroyCount", dataSource.getDestroyCount()); + map.put("ConnectCount", dataSource.getConnectCount()); + + // 5 - 9 + map.put("CloseCount", dataSource.getCloseCount()); + map.put("ActiveCount", dataSource.getActivePeak()); + map.put("PoolingCount", dataSource.getPoolingCount()); + map.put("LockQueueLength", dataSource.getLockQueueLength()); + map.put("WaitThreadCount", dataSource.getNotEmptyWaitThreadPeak()); + + // 10 - 14 + map.put("InitialSize", dataSource.getInitialSize()); + map.put("MaxActive", dataSource.getMaxActive()); + map.put("MinIdle", dataSource.getMinIdle()); + map.put("PoolPreparedStatements", dataSource.isPoolPreparedStatements()); + map.put("TestOnBorrow", dataSource.isTestOnBorrow()); + + // 15 - 19 + map.put("TestOnReturn", dataSource.isTestOnReturn()); + map.put("MinEvictableIdleTimeMillis", dataSource.getMinEvictableIdleTimeMillis()); + map.put("ConnectErrorCount", dataSource.getConnectErrorCount()); + map.put("CreateTimespanMillis", dataSource.getCreateTimespanMillis()); + map.put("DbType", dataSource.getDbType()); + + // 20 - 24 + map.put("ValidationQuery", dataSource.getValidationQuery()); + map.put("ValidationQueryTimeout", dataSource.getValidationQueryTimeout()); + map.put("DriverClassName", dataSource.getDriverClassName()); + map.put("Username", dataSource.getUsername()); + map.put("RemoveAbandonedCount", dataSource.getRemoveAbandonedCount()); + + // 25 - 29 + map.put("NotEmptyWaitCount", dataSource.getNotEmptyWaitCount()); + map.put("NotEmptyWaitNanos", dataSource.getNotEmptyWaitNanos()); + map.put("ErrorCount", dataSource.getErrorCount()); + map.put("ReusePreparedStatementCount", dataSource.getCachedPreparedStatementHitCount()); + map.put("StartTransactionCount", dataSource.getStartTransactionCount()); + + // 30 - 34 + map.put("CommitCount", dataSource.getCommitCount()); + map.put("RollbackCount", dataSource.getRollbackCount()); + map.put("LastError", JMXUtils.getErrorCompositeData(dataSource.getLastError())); + map.put("LastCreateError", JMXUtils.getErrorCompositeData(dataSource.getLastCreateError())); + map.put("PreparedStatementCacheDeleteCount", dataSource.getCachedPreparedStatementDeleteCount()); + + // 35 - 39 + map.put("PreparedStatementCacheAccessCount", dataSource.getCachedPreparedStatementAccessCount()); + map.put("PreparedStatementCacheMissCount", dataSource.getCachedPreparedStatementMissCount()); + map.put("PreparedStatementCacheHitCount", dataSource.getCachedPreparedStatementHitCount()); + map.put("PreparedStatementCacheCurrentCount", dataSource.getCachedPreparedStatementCount()); + map.put("Version", dataSource.getVersion()); + + // 40 - + map.put("LastErrorTime", dataSource.getLastErrorTime()); + map.put("LastCreateErrorTime", dataSource.getLastCreateErrorTime()); + map.put("CreateErrorCount", dataSource.getCreateErrorCount()); + map.put("DiscardCount", dataSource.getDiscardCount()); return new CompositeDataSupport(rowType, map); } diff --git a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java.BASE.java b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java.BASE.java new file mode 100644 index 0000000000..efa89be2a2 --- /dev/null +++ b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java.BASE.java @@ -0,0 +1,75 @@ +package com.alibaba.druid.stat; + +import java.util.List; +import java.util.Map; + +/** + * 监控相关的对外数据暴露 + * + *
+ * 1. 为了支持jndi数据源本类内部调用druid相关对象均需要反射调用,返回值也应该是Object,List,Map等无关于druid的类型
+ * 2. 对外暴露的public方法都应该先调用init(),应该有更好的方式,暂时没想到
+ * 
+ * 
+ * @author sandzhang
+ */
+public class DruidStatManagerFacade {
+
+    private final static DruidStatManagerFacade       instance = new DruidStatManagerFacade();
+
+    private static DruidDataSourceStatStrategyContext ctx      = null;
+
+    private static DruidDataSourceStatStrategy        strategy = null;
+
+    static {
+        strategy = new DruidDataSourceStatJNDIStatStrategy();
+        ctx = new DruidDataSourceStatStrategyContext(strategy);
+    }
+
+    private DruidStatManagerFacade(){
+    }
+
+    public static DruidStatManagerFacade getInstance() {
+        return instance;
+    }
+
+    public Map getSqlStatData(Integer id) {
+        return ctx.getSqlStatData(id);
+    }
+
+    public List> getSqlStatDataList() {
+        return ctx.getSqlStatDataList();
+    }
+
+    public List getActiveConnectionStackTraceByDataSourceId(Integer id) {
+        return ctx.getActiveConnectionStackTraceByDataSourceId(id);
+    }
+
+    public Map returnJSONBasicStat() {
+        return ctx.returnJSONBasicStat();
+    }
+
+    public List getDataSourceStatList() {
+        return ctx.getDataSourceStatList();
+    }
+
+    public Map getDataSourceStatData(Integer id) {
+        return ctx.getDataSourceStatData(id);
+    }
+
+    public List> getPoolingConnectionInfoByDataSourceId(Integer id) {
+        return ctx.getPoolingConnectionInfoByDataSourceId(id);
+    }
+
+    public void resetAll() {
+        ctx.resetAll();
+    }
+
+    public Object getDruidDataSourceById(Integer id) {
+        return ctx.getDruidDataSourceById(id);
+    }
+
+    public Object getSqlStatById(Integer id) {
+        return ctx.getSqlStatById(id);
+    }
+}
diff --git a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java.LOCAL.java b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java.LOCAL.java
new file mode 100644
index 0000000000..864e6d8a09
--- /dev/null
+++ b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java.LOCAL.java
@@ -0,0 +1,75 @@
+package com.alibaba.druid.stat;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 监控相关的对外数据暴露
+ * 
+ * 
+ * 1. 为了支持jndi数据源本类内部调用druid相关对象均需要反射调用,返回值也应该是Object,List,Map等无关于druid的类型
+ * 2. 对外暴露的public方法都应该先调用init(),应该有更好的方式,暂时没想到
+ * 
+ * 
+ * @author sandzhang
+ */
+public class DruidStatManagerFacade {
+
+    private final static DruidStatManagerFacade       instance = new DruidStatManagerFacade();
+
+    private static DruidDataSourceStatStrategyContext ctx      = null;
+
+    private static DruidDataSourceStatStrategy        strategy = null;
+
+    static {
+        strategy = new DruidDataSourceStatReflectStatStrategy();
+        ctx = new DruidDataSourceStatStrategyContext(strategy);
+    }
+
+    private DruidStatManagerFacade(){
+    }
+
+    public static DruidStatManagerFacade getInstance() {
+        return instance;
+    }
+
+    public Map getSqlStatData(Integer id) {
+        return ctx.getSqlStatData(id);
+    }
+
+    public List> getSqlStatDataList() {
+        return ctx.getSqlStatDataList();
+    }
+
+    public List getActiveConnectionStackTraceByDataSourceId(Integer id) {
+        return ctx.getActiveConnectionStackTraceByDataSourceId(id);
+    }
+
+    public Map returnJSONBasicStat() {
+        return ctx.returnJSONBasicStat();
+    }
+
+    public List getDataSourceStatList() {
+        return ctx.getDataSourceStatList();
+    }
+
+    public Map getDataSourceStatData(Integer id) {
+        return ctx.getDataSourceStatData(id);
+    }
+
+    public List> getPoolingConnectionInfoByDataSourceId(Integer id) {
+        return ctx.getPoolingConnectionInfoByDataSourceId(id);
+    }
+
+    public void resetAll() {
+        ctx.resetAll();
+    }
+
+    public Object getDruidDataSourceById(Integer id) {
+        return ctx.getDruidDataSourceById(id);
+    }
+
+    public Object getSqlStatById(Integer id) {
+        return ctx.getSqlStatById(id);
+    }
+}
diff --git a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java.REMOTE.java b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java.REMOTE.java
new file mode 100644
index 0000000000..c84ba7d3d7
--- /dev/null
+++ b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java.REMOTE.java
@@ -0,0 +1,168 @@
+package com.alibaba.druid.stat;
+
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.alibaba.druid.VERSION;
+import com.alibaba.druid.util.DruidDataSourceUtils;
+import com.alibaba.druid.util.JdbcSqlStatUtils;
+
+/**
+ * 监控相关的对外数据暴露
+ * 
+ * 
+ * 1. 为了支持jndi数据源本类内部调用druid相关对象均需要反射调用,返回值也应该是Object,List,Map等无关于druid的类型
+ * 2. 对外暴露的public方法都应该先调用init(),应该有更好的方式,暂时没想到
+ * 
+ * 
+ * @author sandzhang
+ */
+public class DruidStatManagerFacade {
+
+    private final static DruidStatManagerFacade instance = new DruidStatManagerFacade();
+
+    private DruidStatManagerFacade(){
+    }
+
+    public static DruidStatManagerFacade getInstance() {
+        return instance;
+    }
+
+    private Set getDruidDataSourceInstances() {
+        return DruidDataSourceStatManager.getInstances().keySet();
+    }
+
+    public void resetDataSourceStat() {
+        DruidDataSourceStatManager.getInstance().reset();
+    }
+
+    public void resetSqlStat() {
+        JdbcStatManager.getInstance().reset();
+    }
+
+    public void resetAll() {
+        resetSqlStat();
+        resetDataSourceStat();
+    }
+
+    public Object getSqlStatById(Integer id) {
+        for (Object ds : getDruidDataSourceInstances()) {
+            Object sqlStat = DruidDataSourceUtils.getSqlStat(ds, id);
+            if (sqlStat != null) {
+                return sqlStat;
+            }
+        }
+        return null;
+    }
+
+    public Map getDataSourceStatData(Integer id) {
+        if (id == null) {
+            return null;
+        }
+
+        Object datasource = getDruidDataSourceById(id);
+        return datasource == null ? null : dataSourceToMapData(datasource);
+    }
+
+    public Object getDruidDataSourceById(Integer identity) {
+        if (identity == null) {
+            return null;
+        }
+
+        for (Object datasource : getDruidDataSourceInstances()) {
+            if (System.identityHashCode(datasource) == identity) {
+                return datasource;
+            }
+        }
+        return null;
+    }
+
+    public List> getSqlStatDataList() {
+        List> result = new ArrayList>();
+        for (Object datasource : getDruidDataSourceInstances()) {
+            for (Object sqlStat : DruidDataSourceUtils.getSqlStatMap(datasource).values()) {
+
+                Map data = JdbcSqlStatUtils.getData(sqlStat);
+
+                long executeCount = (Long) data.get("ExecuteCount");
+                long runningCount = (Long) data.get("RunningCount");
+
+                if (executeCount == 0 && runningCount == 0) {
+                    continue;
+                }
+
+                result.add(data);
+            }
+        }
+        return result;
+    }
+
+    public Map getSqlStatData(Integer id) {
+        if (id == null) {
+            return null;
+        }
+
+        Object sqlStat = getSqlStatById(id);
+
+        if (sqlStat == null) {
+            return null;
+        }
+
+        return JdbcSqlStatUtils.getData(sqlStat);
+    }
+
+    public List getDataSourceStatList() {
+        List datasourceList = new ArrayList();
+        for (Object dataSource : getDruidDataSourceInstances()) {
+            datasourceList.add(dataSourceToMapData(dataSource));
+        }
+        return datasourceList;
+    }
+
+    public Map returnJSONBasicStat() {
+        Map dataMap = new LinkedHashMap();
+        dataMap.put("Version", VERSION.getVersionNumber());
+        dataMap.put("Drivers", getDriversData());
+        return dataMap;
+    }
+
+    private List getDriversData() {
+        List drivers = new ArrayList();
+        for (Enumeration e = DriverManager.getDrivers(); e.hasMoreElements();) {
+            Driver driver = e.nextElement();
+            drivers.add(driver.getClass().getName());
+        }
+        return drivers;
+    }
+
+    public List> getPoolingConnectionInfoByDataSourceId(Integer id) {
+        Object datasource = getDruidDataSourceById(id);
+
+        if (datasource == null) {
+            return null;
+        }
+
+        return DruidDataSourceUtils.getPoolingConnectionInfo(datasource);
+    }
+
+    public List getActiveConnectionStackTraceByDataSourceId(Integer id) {
+        Object datasource = getDruidDataSourceById(id);
+
+        if (datasource == null || DruidDataSourceUtils.isRemoveAbandoned(datasource)) {
+            return null;
+        }
+
+        return DruidDataSourceUtils.getActiveConnectionStackTrace(datasource);
+    }
+
+    private Map dataSourceToMapData(Object dataSource) {
+
+        return DruidDataSourceUtils.getStatData(dataSource);
+    }
+}
diff --git a/src/main/java/com/alibaba/druid/stat/ReflectStatStrategy.java b/src/main/java/com/alibaba/druid/stat/ReflectStatStrategy.java
new file mode 100644
index 0000000000..c42c922998
--- /dev/null
+++ b/src/main/java/com/alibaba/druid/stat/ReflectStatStrategy.java
@@ -0,0 +1,11 @@
+package com.alibaba.druid.stat;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
+public abstract class ReflectStatStrategy {
+
+    public final static HashMap> methodHM = new HashMap>();
+
+    public abstract Object invoke(Object obj, String methodName, Integer id);
+}
diff --git a/src/main/java/com/alibaba/druid/util/DruidDataSourceUtils.java b/src/main/java/com/alibaba/druid/util/DruidDataSourceUtils.java
index 49dc8d1741..41a2e1807f 100644
--- a/src/main/java/com/alibaba/druid/util/DruidDataSourceUtils.java
+++ b/src/main/java/com/alibaba/druid/util/DruidDataSourceUtils.java
@@ -81,7 +81,7 @@ public class DruidDataSourceUtils {
         }
     }
 
-    @SuppressWarnings({ "rawtypes" })
+    @SuppressWarnings("unchecked")
     public static Map getSqlStatMap(Object druidDatasource) {
         try {
             Method method = druidDatasource.getClass().getMethod("getSqlStatMap");