diff --git a/src/main/java/com/alibaba/druid/support/JSONDruidStatService.java b/src/main/java/com/alibaba/druid/support/JSONDruidStatService.java index c0349b5c0f..09523a81f3 100644 --- a/src/main/java/com/alibaba/druid/support/JSONDruidStatService.java +++ b/src/main/java/com/alibaba/druid/support/JSONDruidStatService.java @@ -7,6 +7,7 @@ import java.util.Map; import com.alibaba.druid.stat.DruidStatManagerFacade; import com.alibaba.druid.support.http.stat.WebAppStatManager; +import com.alibaba.druid.support.spring.stat.SpringStatManager; import com.alibaba.druid.util.MapComparator; import com.alibaba.druid.util.StringUtils; import com.alibaba.fastjson.JSON; @@ -90,10 +91,19 @@ public class JSONDruidStatService { if (url.startsWith("/websession.json")) { return returnJSONResult(RESULT_CODE_SUCCESS, getWebSessionStatDataList(parameters)); } + + if (url.startsWith("/spring.json")) { + return returnJSONResult(RESULT_CODE_SUCCESS, getSpringStatDataList(parameters)); + } return returnJSONResult(RESULT_CODE_ERROR, "Do not support this request, please contact with administrator."); } + private List> getSpringStatDataList(Map parameters) { + List> array = SpringStatManager.getInstance().getMethodStatData(); + return comparatorOrderBy(array, parameters); + } + private List> getWebURIStatDataList(Map parameters) { List> array = WebAppStatManager.getInstance().getURIStatData(); return comparatorOrderBy(array, parameters); diff --git a/src/main/java/com/alibaba/druid/support/http/WebStatFilter.java b/src/main/java/com/alibaba/druid/support/http/WebStatFilter.java index bfcbba7159..687a9a7e6f 100644 --- a/src/main/java/com/alibaba/druid/support/http/WebStatFilter.java +++ b/src/main/java/com/alibaba/druid/support/http/WebStatFilter.java @@ -22,6 +22,7 @@ import com.alibaba.druid.support.http.stat.WebRequestStat; import com.alibaba.druid.support.http.stat.WebSessionStat; import com.alibaba.druid.support.logging.Log; import com.alibaba.druid.support.logging.LogFactory; +import com.alibaba.druid.support.spring.stat.SpringMethodStat; import com.alibaba.druid.util.DruidWebUtils; import com.alibaba.druid.util.PatternMatcher; import com.alibaba.druid.util.ServletPathMatcher; @@ -264,49 +265,79 @@ public class WebStatFilter implements Filter { @Override public void addUpdateCount(int updateCount) { - WebRequestStat localStat = WebRequestStat.current(); - if (localStat != null) { - localStat.addJdbcUpdateCount(updateCount); + WebRequestStat reqStat = WebRequestStat.current(); + if (reqStat != null) { + reqStat.addJdbcUpdateCount(updateCount); + } + + SpringMethodStat springMethodStat = SpringMethodStat.current(); + if (springMethodStat != null) { + springMethodStat.addJdbcUpdateCount(updateCount); } } @Override public void addFetchRowCount(int fetchRowCount) { - WebRequestStat localStat = WebRequestStat.current(); - if (localStat != null) { - localStat.addJdbcFetchRowCount(fetchRowCount); + WebRequestStat reqStat = WebRequestStat.current(); + if (reqStat != null) { + reqStat.addJdbcFetchRowCount(fetchRowCount); + } + + SpringMethodStat springMethodStat = SpringMethodStat.current(); + if (springMethodStat != null) { + springMethodStat.addJdbcFetchRowCount(fetchRowCount); } } @Override public void executeBefore(String sql, boolean inTransaction) { - WebRequestStat localStat = WebRequestStat.current(); - if (localStat != null) { - localStat.incrementJdbcExecuteCount(); + WebRequestStat reqStat = WebRequestStat.current(); + if (reqStat != null) { + reqStat.incrementJdbcExecuteCount(); + } + + SpringMethodStat springMethodStat = SpringMethodStat.current(); + if (springMethodStat != null) { + springMethodStat.incrementJdbcExecuteCount(); } } @Override - public void executeAfter(String sql, long nanoSpan, Throwable error) { - WebRequestStat localStat = WebRequestStat.current(); - if (localStat != null) { - localStat.addJdbcExecuteNano(nanoSpan); + public void executeAfter(String sql, long nanos, Throwable error) { + WebRequestStat reqStat = WebRequestStat.current(); + if (reqStat != null) { + reqStat.addJdbcExecuteTimeNano(nanos); + } + + SpringMethodStat springMethodStat = SpringMethodStat.current(); + if (springMethodStat != null) { + springMethodStat.addJdbcExecuteTimeNano(nanos); } } @Override public void commit() { - WebRequestStat localStat = WebRequestStat.current(); - if (localStat != null) { - localStat.incrementJdbcCommitCount(); + WebRequestStat reqStat = WebRequestStat.current(); + if (reqStat != null) { + reqStat.incrementJdbcCommitCount(); + } + + SpringMethodStat springMethodStat = SpringMethodStat.current(); + if (springMethodStat != null) { + springMethodStat.incrementJdbcCommitCount(); } } @Override public void rollback() { - WebRequestStat localStat = WebRequestStat.current(); - if (localStat != null) { - localStat.incrementJdbcRollbackCount(); + WebRequestStat reqStat = WebRequestStat.current(); + if (reqStat != null) { + reqStat.incrementJdbcRollbackCount(); + } + + SpringMethodStat springMethodStat = SpringMethodStat.current(); + if (springMethodStat != null) { + springMethodStat.incrementJdbcRollbackCount(); } } } diff --git a/src/main/java/com/alibaba/druid/support/http/stat/WebRequestStat.java b/src/main/java/com/alibaba/druid/support/http/stat/WebRequestStat.java index 17f89e313d..36b9d68200 100644 --- a/src/main/java/com/alibaba/druid/support/http/stat/WebRequestStat.java +++ b/src/main/java/com/alibaba/druid/support/http/stat/WebRequestStat.java @@ -61,11 +61,11 @@ public class WebRequestStat { return jdbcExecuteCount; } - public long getJdbcExecuteNano() { + public long getJdbcExecuteTimeNano() { return jdbcExecuteNano; } - public void addJdbcExecuteNano(long nano) { + public void addJdbcExecuteTimeNano(long nano) { jdbcExecuteNano += nano; } diff --git a/src/main/java/com/alibaba/druid/support/http/stat/WebSessionStat.java b/src/main/java/com/alibaba/druid/support/http/stat/WebSessionStat.java index 07e565af18..8adb6c4a54 100644 --- a/src/main/java/com/alibaba/druid/support/http/stat/WebSessionStat.java +++ b/src/main/java/com/alibaba/druid/support/http/stat/WebSessionStat.java @@ -135,7 +135,7 @@ public class WebSessionStat { this.addJdbcUpdateCount(requestStat.getJdbcUpdateCount()); this.addJdbcCommitCount(requestStat.getJdbcCommitCount()); this.addJdbcRollbackCount(requestStat.getJdbcRollbackCount()); - this.addJdbcExecuteTimeNano(requestStat.getJdbcExecuteNano()); + this.addJdbcExecuteTimeNano(requestStat.getJdbcExecuteTimeNano()); } } diff --git a/src/main/java/com/alibaba/druid/support/spring/stat/BeanTypeAutoProxyCreator.java b/src/main/java/com/alibaba/druid/support/spring/stat/BeanTypeAutoProxyCreator.java new file mode 100644 index 0000000000..ed61feab90 --- /dev/null +++ b/src/main/java/com/alibaba/druid/support/spring/stat/BeanTypeAutoProxyCreator.java @@ -0,0 +1,87 @@ +package com.alibaba.druid.support.spring.stat; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.springframework.aop.TargetSource; +import org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.util.Assert; +import org.springframework.util.PatternMatchUtils; + +/** + * 类BeanTypeAutoProxyCreator.java的实现描述:使用配置类型代替Springframework中配置名称的实现 + * + * @author hualiang.lihl 2011-12-31 上午10:48:20 + */ +public class BeanTypeAutoProxyCreator extends AbstractAutoProxyCreator implements InitializingBean, ApplicationContextAware { + + private static final long serialVersionUID = -9094985530794052264L; + + private Class targetBeanType; + + private ApplicationContext context; + + private List beanNames = new ArrayList(); + + /** + * @param targetClass the targetClass to set + */ + public void setTargetBeanType(Class targetClass) { + this.targetBeanType = targetClass; + } + + public void setApplicationContext(ApplicationContext context) throws BeansException { + this.context = context; + } + + /** + * Identify as bean to proxy if the bean name is in the configured list of names. + */ + @SuppressWarnings("rawtypes") + protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) { + for (Iterator it = this.beanNames.iterator(); it.hasNext();) { + String mappedName = (String) it.next(); + if (FactoryBean.class.isAssignableFrom(beanClass)) { + if (!mappedName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { + continue; + } + mappedName = mappedName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); + } + if (isMatch(beanName, mappedName)) { + return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS; + } + } + return DO_NOT_PROXY; + } + + /** + * Return if the given bean name matches the mapped name. + *

+ * The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, as well as direct equality. Can be + * overridden in subclasses. + * + * @param beanName the bean name to check + * @param mappedName the name in the configured list of names + * @return if the names match + * @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String) + */ + protected boolean isMatch(String beanName, String mappedName) { + return PatternMatchUtils.simpleMatch(mappedName, beanName); + } + + public void afterPropertiesSet() throws Exception { + Assert.notNull(targetBeanType, "targetType cannot be null"); + String[] beanNames = context.getBeanNamesForType(targetBeanType); + for (String name : beanNames) { + this.beanNames.add(name); + } + } + +} diff --git a/src/main/java/com/alibaba/druid/support/spring/stat/DruidStatInterceptor.java b/src/main/java/com/alibaba/druid/support/spring/stat/DruidStatInterceptor.java new file mode 100644 index 0000000000..c8eb99ed41 --- /dev/null +++ b/src/main/java/com/alibaba/druid/support/spring/stat/DruidStatInterceptor.java @@ -0,0 +1,128 @@ +package com.alibaba.druid.support.spring.stat; + +import java.lang.reflect.Method; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.aop.TargetSource; +import org.springframework.beans.factory.InitializingBean; + +import com.alibaba.druid.support.logging.Log; +import com.alibaba.druid.support.logging.LogFactory; + +public class DruidStatInterceptor implements MethodInterceptor, InitializingBean { + + private final static Log LOG = LogFactory.getLog(DruidStatInterceptor.class); + + private static SpringStat springStat = new SpringStat(); + + public DruidStatInterceptor() { + + } + + @Override + public void afterPropertiesSet() throws Exception { + SpringStatManager.getInstance().addSpringStat(springStat); + } + + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { + SpringMethodStat lastMethodStat = SpringMethodStat.current(); + + MethodInfo methodInfo = getMethodInfo(invocation); + + SpringMethodStat methodStat = springStat.getMethodStat(methodInfo, true); + + if (methodStat != null) { + methodStat.beforeInvoke(); + } + + long startNanos = System.nanoTime(); + + Throwable error = null; + try { + Object returnObject = invocation.proceed(); + + return returnObject; + } catch (Throwable e) { + error = e; + throw e; + } finally { + long endNanos = System.nanoTime(); + + long nanos = endNanos - startNanos; + + if (methodStat != null) { + methodStat.afterInvoke(error, nanos); + } + + SpringMethodStat.setCurrent(lastMethodStat); + } + } + + public MethodInfo getMethodInfo(MethodInvocation invocation) { + Object thisObject = invocation.getThis(); + Method method = invocation.getMethod(); + + if (thisObject == null) { + return new MethodInfo(method.getDeclaringClass(), method); + } + + if (method.getDeclaringClass() == thisObject.getClass()) { + return new MethodInfo(method.getDeclaringClass(), method); + } + + { + Class clazz = thisObject.getClass(); + boolean isCglibProxy = false; + boolean isJavassistProxy = false; + for (Class item : clazz.getInterfaces()) { + if (item.getName().equals("net.sf.cglib.proxy.Factory")) { + isCglibProxy = true; + break; + } else if (item.getName().equals("javassist.util.proxy.ProxyObject")) { + isJavassistProxy = true; + break; + } + } + + if (isCglibProxy || isJavassistProxy) { + Class superClazz = clazz.getSuperclass(); + + return new MethodInfo(superClazz, method); + } + } + + Class clazz = null; + try { + // 最多支持10层代理 + for (int i = 0; i < 10; ++i) { + if (thisObject instanceof org.springframework.aop.framework.Advised) { + TargetSource targetSource = ((org.springframework.aop.framework.Advised) thisObject).getTargetSource(); + + if (targetSource == null) { + break; + } + + Object target = targetSource.getTarget(); + if (target != null) { + thisObject = target; + } else { + clazz = targetSource.getTargetClass(); + break; + } + } else { + break; + } + } + } catch (Exception ex) { + LOG.error("getMethodInfo error", ex); + } + + if (clazz == null) { + return new MethodInfo(method.getDeclaringClass(), method); + } + + return new MethodInfo(clazz, method); + } +} diff --git a/src/main/java/com/alibaba/druid/support/spring/stat/MethodInfo.java b/src/main/java/com/alibaba/druid/support/spring/stat/MethodInfo.java new file mode 100644 index 0000000000..03b715e981 --- /dev/null +++ b/src/main/java/com/alibaba/druid/support/spring/stat/MethodInfo.java @@ -0,0 +1,83 @@ +package com.alibaba.druid.support.spring.stat; + +import java.lang.reflect.Method; + +public class MethodInfo { + + private final Class instanceClass; + private final Method method; + private final String signature; + + public MethodInfo(Class instanceClass, Method method){ + super(); + this.instanceClass = instanceClass; + this.method = method; + signature = getMethodSignature(this.getMethod()); + } + + public Class getInstanceClass() { + return instanceClass; + } + + public Method getMethod() { + return method; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((instanceClass == null) ? 0 : instanceClass.hashCode()); + result = prime * result + ((method == null) ? 0 : method.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + MethodInfo other = (MethodInfo) obj; + + if (instanceClass != other.instanceClass) { + return false; + } + + if (signature == null) { + return other.signature == null; + } + + if (!signature.equals(other.signature)) { + return false; + } + + return true; + } + + public static String getMethodSignature(Method method) { + StringBuffer sb = new StringBuffer(); + + sb.append(method.getName() + "("); + Class[] params = method.getParameterTypes(); + for (int j = 0; j < params.length; j++) { + sb.append(params[j].getName()); + if (j < (params.length - 1)) sb.append(","); + } + sb.append(")"); + + return sb.toString(); + } + + public String getSignature() { + return signature; + } +} diff --git a/src/main/java/com/alibaba/druid/support/spring/stat/SpringMethodStat.java b/src/main/java/com/alibaba/druid/support/spring/stat/SpringMethodStat.java new file mode 100644 index 0000000000..66e87d6e36 --- /dev/null +++ b/src/main/java/com/alibaba/druid/support/spring/stat/SpringMethodStat.java @@ -0,0 +1,184 @@ +package com.alibaba.druid.support.spring.stat; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +public class SpringMethodStat { + + private final static ThreadLocal currentLocal = new ThreadLocal(); + + private final MethodInfo methodInfo; + + private final AtomicInteger runningCount = new AtomicInteger(); + private final AtomicInteger concurrentMax = new AtomicInteger(); + private final AtomicLong executeCount = new AtomicLong(0); + private final AtomicLong executeErrorCount = new AtomicLong(0); + private final AtomicLong executeTimeNano = new AtomicLong(); + + private final AtomicLong jdbcFetchRowCount = new AtomicLong(); + private final AtomicLong jdbcUpdateCount = new AtomicLong(); + private final AtomicLong jdbcExecuteCount = new AtomicLong(); + private final AtomicLong jdbcExecuteTimeNano = new AtomicLong(); + + private final AtomicLong jdbcCommitCount = new AtomicLong(); + private final AtomicLong jdbcRollbackCount = new AtomicLong(); + + public SpringMethodStat(MethodInfo methodInfo){ + this.methodInfo = methodInfo; + } + + public MethodInfo getMethodInfo() { + return methodInfo; + } + + public static SpringMethodStat current() { + return currentLocal.get(); + } + + public static void setCurrent(SpringMethodStat current) { + currentLocal.set(current); + } + + public void beforeInvoke() { + currentLocal.set(this); + + int running = runningCount.incrementAndGet(); + + for (;;) { + int max = concurrentMax.get(); + if (running > max) { + if (concurrentMax.compareAndSet(max, running)) { + break; + } else { + continue; + } + } else { + break; + } + } + + executeCount.incrementAndGet(); + } + + public void afterInvoke(Throwable error, long nanos) { + runningCount.decrementAndGet(); + executeTimeNano.addAndGet(nanos); + + if (error != null) { + executeErrorCount.incrementAndGet(); + } + } + + public int getRunningCount() { + return this.runningCount.get(); + } + + public long getConcurrentMax() { + return concurrentMax.get(); + } + + public long getExecuteCount() { + return executeCount.get(); + } + + public long getExecuteErrorCount() { + return executeErrorCount.get(); + } + + public long getExecuteTimeNano() { + return executeTimeNano.get(); + } + + public long getExecuteTimeMillis() { + return getExecuteTimeNano() / (1000 * 1000); + } + + public void addJdbcFetchRowCount(long delta) { + this.jdbcFetchRowCount.addAndGet(delta); + } + + public long getJdbcFetchRowCount() { + return jdbcFetchRowCount.get(); + } + + public void addJdbcUpdateCount(long updateCount) { + this.jdbcUpdateCount.addAndGet(updateCount); + } + + public long getJdbcUpdateCount() { + return jdbcUpdateCount.get(); + } + + public void incrementJdbcExecuteCount() { + jdbcExecuteCount.incrementAndGet(); + } + + public void addJdbcExecuteCount(long executeCount) { + jdbcExecuteCount.addAndGet(executeCount); + } + + public long getJdbcExecuteCount() { + return jdbcExecuteCount.get(); + } + + public long getJdbcExecuteTimeMillis() { + return getJdbcExecuteTimeNano() / (1000 * 1000); + } + + public long getJdbcExecuteTimeNano() { + return jdbcExecuteTimeNano.get(); + } + + public void addJdbcExecuteTimeNano(long nano) { + jdbcExecuteTimeNano.addAndGet(nano); + } + + public void incrementJdbcCommitCount() { + jdbcCommitCount.incrementAndGet(); + } + + public long getJdbcCommitCount() { + return jdbcCommitCount.get(); + } + + public void addJdbcCommitCount(long commitCount) { + this.jdbcCommitCount.addAndGet(commitCount); + } + + public void incrementJdbcRollbackCount() { + jdbcRollbackCount.incrementAndGet(); + } + + public long getJdbcRollbackCount() { + return jdbcRollbackCount.get(); + } + + public void addJdbcRollbackCount(long rollbackCount) { + this.jdbcRollbackCount.addAndGet(rollbackCount); + } + + public Map getStatData() { + Map data = new LinkedHashMap(); + + data.put("Class", this.getMethodInfo().getInstanceClass().getName()); + data.put("Method", this.getMethodInfo().getSignature()); + + data.put("RunningCount", this.getRunningCount()); + data.put("ConcurrentMax", this.getConcurrentMax()); + data.put("ExecuteCount", this.getExecuteCount()); + data.put("ExecuteErrorCount", this.getExecuteErrorCount()); + data.put("ExecuteTimeMillis", this.getExecuteTimeMillis()); + + data.put("JdbcCommitCount", this.getJdbcCommitCount()); + data.put("JdbcRollbackCount", this.getJdbcRollbackCount()); + + data.put("JdbcExecuteCount", this.getJdbcExecuteCount()); + data.put("JdbcExecuteTimeMillis", this.getJdbcExecuteTimeMillis()); + data.put("JdbcFetchRowCount", this.getJdbcFetchRowCount()); + data.put("JdbcUpdateCount", this.getJdbcUpdateCount()); + + return data; + } +} diff --git a/src/main/java/com/alibaba/druid/support/spring/stat/SpringStat.java b/src/main/java/com/alibaba/druid/support/spring/stat/SpringStat.java new file mode 100644 index 0000000000..748d687142 --- /dev/null +++ b/src/main/java/com/alibaba/druid/support/spring/stat/SpringStat.java @@ -0,0 +1,47 @@ +package com.alibaba.druid.support.spring.stat; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +public class SpringStat { + + private ConcurrentMap methodStats = new ConcurrentHashMap(); + + public SpringStat(){ + + } + + public SpringMethodStat getMethodStat(MethodInfo methodInfo, boolean create) { + SpringMethodStat methodStat = methodStats.get(methodInfo); + if (methodStat != null) { + return methodStat; + } + + if (create) { + methodStats.putIfAbsent(methodInfo, new SpringMethodStat(methodInfo)); + methodStat = methodStats.get(methodInfo); + } + + return methodStat; + } + + public List> getMethodStatDataList() { + List> methodStatDataList = new ArrayList>(this.methodStats.size()); + for (SpringMethodStat methodStat : this.methodStats.values()) { + Map methodStatData = methodStat.getStatData(); + + int runningCount = ((Number) methodStatData.get("RunningCount")).intValue(); + long executeCount = (Long) methodStatData.get("ExecuteCount"); + + if (runningCount == 0 && executeCount == 0) { + continue; + } + + methodStatDataList.add(methodStatData); + } + return methodStatDataList; + } +} diff --git a/src/main/java/com/alibaba/druid/support/spring/stat/SpringStatManager.java b/src/main/java/com/alibaba/druid/support/spring/stat/SpringStatManager.java new file mode 100644 index 0000000000..77363601ef --- /dev/null +++ b/src/main/java/com/alibaba/druid/support/spring/stat/SpringStatManager.java @@ -0,0 +1,65 @@ +package com.alibaba.druid.support.spring.stat; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +public class SpringStatManager { + + public final static String SYS_PROP_INSTANCES = "druid.spring.springStat"; + + private final static SpringStatManager instance = new SpringStatManager(); + + private Set springStatSet = null; + + public static SpringStatManager getInstance() { + return instance; + } + + public Set getSpringStatSet() { + if (springStatSet == null) { + springStatSet = getSpringStatSetFromSysProperty(); + } + + return springStatSet; + } + + public void addSpringStat(Object springStat) { + getSpringStatSet().add(springStat); + } + + @SuppressWarnings("unchecked") + static Set getSpringStatSetFromSysProperty() { + Properties properties = System.getProperties(); + Set webAppStats = (Set) properties.get(SYS_PROP_INSTANCES); + + if (webAppStats == null) { + synchronized (properties) { + webAppStats = (Set) properties.get(SYS_PROP_INSTANCES); + + if (webAppStats == null) { + webAppStats = new CopyOnWriteArraySet(); + properties.put(SYS_PROP_INSTANCES, webAppStats); + } + } + } + + return webAppStats; + } + + public List> getMethodStatData() { + Set stats = getSpringStatSet(); + + List> allMethodStatDataList = new ArrayList>(); + + for (Object stat : stats) { + List> methodStatDataList = SpringStatUtils.getMethodStatDataList(stat); + allMethodStatDataList.addAll(methodStatDataList); + } + + return allMethodStatDataList; + } +} diff --git a/src/main/java/com/alibaba/druid/support/spring/stat/SpringStatUtils.java b/src/main/java/com/alibaba/druid/support/spring/stat/SpringStatUtils.java new file mode 100644 index 0000000000..11e7cfa0a3 --- /dev/null +++ b/src/main/java/com/alibaba/druid/support/spring/stat/SpringStatUtils.java @@ -0,0 +1,29 @@ +package com.alibaba.druid.support.spring.stat; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; + +import com.alibaba.druid.support.logging.Log; +import com.alibaba.druid.support.logging.LogFactory; + +public class SpringStatUtils { + + private final static Log LOG = LogFactory.getLog(SpringStatUtils.class); + + @SuppressWarnings("unchecked") + public static List> getMethodStatDataList(Object methodStat) { + if (methodStat.getClass() == SpringStat.class) { + return ((SpringStat) methodStat).getMethodStatDataList(); + } + + try { + Method method = methodStat.getClass().getMethod("getMethodStatDataList"); + Object obj = method.invoke(methodStat); + return (List>) obj; + } catch (Exception e) { + LOG.error("getMethodStatDataList error", e); + return null; + } + } +} diff --git a/src/main/resources/support/http/resources/activeConnectionStackTrace.html b/src/main/resources/support/http/resources/activeConnectionStackTrace.html index 9e4d0a90b8..85ac4e1e47 100644 --- a/src/main/resources/support/http/resources/activeConnectionStackTrace.html +++ b/src/main/resources/support/http/resources/activeConnectionStackTrace.html @@ -16,7 +16,7 @@

diff --git a/src/main/resources/support/http/resources/api.html b/src/main/resources/support/http/resources/api.html index 687a2bf3dc..7aeef92d98 100644 --- a/src/main/resources/support/http/resources/api.html +++ b/src/main/resources/support/http/resources/api.html @@ -9,7 +9,7 @@

diff --git a/src/main/resources/support/http/resources/connectionInfo.html b/src/main/resources/support/http/resources/connectionInfo.html index c8e3143a82..2ecc1fae60 100644 --- a/src/main/resources/support/http/resources/connectionInfo.html +++ b/src/main/resources/support/http/resources/connectionInfo.html @@ -16,7 +16,7 @@

diff --git a/src/main/resources/support/http/resources/datasource.html b/src/main/resources/support/http/resources/datasource.html index 405c2b0627..4f1a93f655 100644 --- a/src/main/resources/support/http/resources/datasource.html +++ b/src/main/resources/support/http/resources/datasource.html @@ -16,7 +16,7 @@

diff --git a/src/main/resources/support/http/resources/index.html b/src/main/resources/support/http/resources/index.html index 1a8c90464d..13a8b8e75a 100644 --- a/src/main/resources/support/http/resources/index.html +++ b/src/main/resources/support/http/resources/index.html @@ -15,7 +15,7 @@

diff --git a/src/main/resources/support/http/resources/js/spring.js b/src/main/resources/support/http/resources/js/spring.js new file mode 100644 index 0000000000..bb463d6b63 --- /dev/null +++ b/src/main/resources/support/http/resources/js/spring.js @@ -0,0 +1,111 @@ + +var xmlHttpForDataSourceSqlStatInfo; + +var sqlViewOrderBy = ''; +var sqlViewOrderBy_old = ''; +var sqlViewOrderType = 'asc'; + +// only one page for now +var sqlViewPage = 1; +var sqlViewPerPageCount = 1000000; + +function resetSortMark() { + var divObj = document.getElementById('th-' + sqlViewOrderBy); + var old_divObj = document.getElementById('th-' + sqlViewOrderBy_old); + var replaceToStr = ''; + if (old_divObj) { + var html = old_divObj.innerHTML; + if (sqlViewOrderBy_old.indexOf('[') > 0) + replaceToStr = '-'; + html = html.replace('↑', replaceToStr); + html = html.replace('↓', replaceToStr); + old_divObj.innerHTML = html + } + if (divObj) { + var html = divObj.innerHTML; + if (sqlViewOrderBy.indexOf('[') > 0) + html = ''; + + if (sqlViewOrderType == 'asc') { + html += '↑'; + } else if (sqlViewOrderType == 'desc') { + html += '↓'; + } + divObj.innerHTML = html; + } +} + +function setOrderBy(orderBy) { + if (sqlViewOrderBy != orderBy) { + sqlViewOrderBy_old = sqlViewOrderBy; + sqlViewOrderBy = orderBy; + sqlViewOrderType = 'desc'; + resetSortMark(); + return; + } + + sqlViewOrderBy_old = sqlViewOrderBy; + + if (sqlViewOrderType == 'asc') + sqlViewOrderType = 'desc' + else + sqlViewOrderType = 'asc'; + + resetSortMark(); + +} + +function getSqlViewJsonUrl() { + var result = 'spring.json?'; + + if (sqlViewOrderBy != undefined) + result += 'orderBy=' + sqlViewOrderBy + '&'; + + if (sqlViewOrderType != undefined) + result += 'orderType=' + sqlViewOrderType + '&'; + + if (sqlViewPage != undefined) + result += 'page=' + sqlViewPage + '&'; + + if (sqlViewPerPageCount != undefined) + result += 'perPageCount=' + sqlViewPerPageCount + '&'; + + return result; +} + +function ajaxRequestForDataSourceSqlStatInfo() { + xmlHttpForDataSourceSqlStatInfo = getRequestObject(); + sendRequest(xmlHttpForDataSourceSqlStatInfo,getSqlViewJsonUrl(),ajaxResponseForDataSourceSqlStatInfo) +} + +function subSqlString(sql, len) { + if (sql.length <= len) + return sql; + return sql.substr(0, len) + '...'; +} +function ajaxResponseForDataSourceSqlStatInfo() { + var sqlStatList = getJSONResponseContent(xmlHttpForDataSourceSqlStatInfo); + if(sqlStatList==null) return; + + var sqlStatTable = document.getElementById("SpringStatTable"); + while (sqlStatTable.rows.length > 1) { + sqlStatTable.deleteRow(1); + } + for ( var i = 0; i < sqlStatList.length; i++) { + var sqlStat = sqlStatList[i]; + var newRow = sqlStatTable.insertRow(-1); + newRow.insertCell(-1).innerHTML = i+1; + newRow.insertCell(-1).innerHTML = sqlStat.Class; + newRow.insertCell(-1).innerHTML = sqlStat.Method; + newRow.insertCell(-1).innerHTML = sqlStat.ExecuteCount; + newRow.insertCell(-1).innerHTML = sqlStat.ExecuteTimeMillis; + newRow.insertCell(-1).innerHTML = sqlStat.RunningCount; + newRow.insertCell(-1).innerHTML = sqlStat.ConcurrentMax; + newRow.insertCell(-1).innerHTML = sqlStat.JdbcExecuteCount; + newRow.insertCell(-1).innerHTML = sqlStat.JdbcExecuteTimeMillis; + newRow.insertCell(-1).innerHTML = sqlStat.JdbcCommitCount; + newRow.insertCell(-1).innerHTML = sqlStat.JdbcRollbackCount; + newRow.insertCell(-1).innerHTML = sqlStat.JdbcFetchRowCount; + newRow.insertCell(-1).innerHTML = sqlStat.JdbcUpdateCount; + } +} \ No newline at end of file diff --git a/src/main/resources/support/http/resources/spring.html b/src/main/resources/support/http/resources/spring.html new file mode 100644 index 0000000000..a8a735649a --- /dev/null +++ b/src/main/resources/support/http/resources/spring.html @@ -0,0 +1,45 @@ + + + + Druid Web Session Stat + + + + + + + +
+ +
+ + + + \ No newline at end of file diff --git a/src/main/resources/support/http/resources/sql.html b/src/main/resources/support/http/resources/sql.html index 8d91615be0..3836c41ff7 100644 --- a/src/main/resources/support/http/resources/sql.html +++ b/src/main/resources/support/http/resources/sql.html @@ -16,7 +16,7 @@

diff --git a/src/main/resources/support/http/resources/template.html b/src/main/resources/support/http/resources/template.html deleted file mode 100644 index e199f6faac..0000000000 --- a/src/main/resources/support/http/resources/template.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - {title} - - - - - -
- -
-
- {content} -
- - - \ No newline at end of file diff --git a/src/main/resources/support/http/resources/websession.html b/src/main/resources/support/http/resources/websession.html index 675b2e58c7..329a5de25b 100644 --- a/src/main/resources/support/http/resources/websession.html +++ b/src/main/resources/support/http/resources/websession.html @@ -16,7 +16,7 @@

diff --git a/src/main/resources/support/http/resources/weburi.html b/src/main/resources/support/http/resources/weburi.html index 1d5b5debce..e510fded34 100644 --- a/src/main/resources/support/http/resources/weburi.html +++ b/src/main/resources/support/http/resources/weburi.html @@ -16,7 +16,7 @@