这次创建一个自定义注解StopWatch,目的是用来监控Java方法的执行时间。
注解定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package com.zhyea.robin.dev.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.concurrent.TimeUnit; @Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface StopWatch { String name(); TimeUnit timeunit() default TimeUnit.MILLISECONDS; } |
代码中使用到的几个元注解上一节都有说明。注解定义完成了就可以使用了,下面是一个这个注解的使用案例:
1 2 3 4 5 6 7 8 |
@StopWatch(name = "TestAnnotation -> test") public List testAnnotation() { try{ TimeUnit.Seconds.sleep(30);// sleep 30 seconds }catch(Exception e){ // ignore exception } } |
在自定义的注解中使用了两个成员变量:name和timeunit。在使用自定义注解时,需要给成员变量赋值。赋值的方式就是程序中那样:
1 |
@StopWatch(name = "TestAnnotation -> test") |
其中因为timeunit有默认值,所以可以不用额外赋值。 值得一提的是如果只有一个成员变量,且名称为value,可以不用再使用name=value,直接在括号中填上value即可。
但是这个注解能做什么呢?什么也不能做。仅有注解是没有意义的。我们需要为自定义的注解添加一些功能,也就是注解的解析器。
因为一直在Spring平台上做开发,所以注解的解析也依托Spring来做,这里还主要使用了一个组件AspectJ。解析器定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; import package com.zhyea.robin.dev.annotation.Watcher; @Aspect @Component public class StopWatchContract { @Around("execution(* com.zhyea..*.*(..)) && @annotation(sw)") public void handle(final ProceedingJoinPoint pjd, StopWatch sw) throws Throwable { Watcher w = Watcher.getWatcher(); w.setName(sw.name()); w.setTimeUnit(sw.timeunit()); w.start(); try { pjd.proceed(); } finally { w.close(); } } } |
代码中使用的Watcher是简单将计时代码做了一些封装,如有兴趣也可以看一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
import java.io.Closeable; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; public class Watcher implements Closeable, Cloneable { /** 计时统计注册表 */ public static Map<String, WatchUnit> counter; /** 当前计时任务名称 */ private String name; /** 标志是否开始 */ private boolean isStarted; /** 计时开始的时间 */ private long startNanos; /** 当前已经经过的时间 */ private long currentElapsedNanos; /** 当前的计时单位 */ private TimeUnit timeUnit; /** 用来为clone使用 */ private static Watcher watcher = new Watcher(); static { counter = new HashMap<String, WatchUnit>(); } /** * 构造器 */ public Watcher() { } public Watcher(String name) { this.name = name; } public Watcher(String name, TimeUnit timeUnit) { this(name); this.timeUnit = timeUnit; } /** * 用来判断Watcher是否已经启动的方法 * @return * 如Watcher已经启动,返回true;否则,返回 false */ public boolean isRunning() { return isStarted; } /** * 开始时间计量并调整运行标志 * @return * Watcher实例 */ public Watcher start() { if (isStarted) { throw new IllegalStateException("Watcher is already running"); } isStarted = true; startNanos = System.nanoTime(); return this; } /** * 停止时间计量并调整运行标志 * @return * Watcher实例 */ public Watcher stop() { if (!isStarted) { throw new IllegalStateException("Watcher is already stopped"); } long now = System.nanoTime(); isStarted = false; currentElapsedNanos += now - startNanos; return this; } /** * 重置经过的时间为0,并将运行标志调整为false。 * @return * Watcher实例 */ public Watcher reset() { currentElapsedNanos = 0; isStarted = false; return this; } /** * 以指定的TimeUnit计算当前经过的时间 * @return * 当前已经经过的时间 */ public long now(TimeUnit timeUnit) { return timeUnit.convert(now(), TimeUnit.NANOSECONDS); } /** * 当前已经经过的时间,单位纳秒 */ public long now() { return isStarted ? System.nanoTime() - startNanos + currentElapsedNanos : currentElapsedNanos; } /** * 将统计信息转为字符串 */ @Override public String toString() { return String.valueOf(now()); } @Override public void close() { if (isStarted) { stop(); } if (null == timeUnit) { add(now()); } else { add(now(timeUnit)); } } /** * 设置监控名称 * @param name * 监控名称 */ public void setName(String name) { this.name = name; } /** * 设置当前的计时单位 * @param timeUnit * 计时单位 */ public void setTimeUnit(TimeUnit timeUnit) { this.timeUnit = timeUnit; } /** * 累计监控时间 * @param name * 监控名称 * @param elapseTime * 监控时间 */ private void add(long elapseTime) { WatchUnit wu = counter.get(name); if (null == wu) { wu = new WatchUnit(name); } wu.add(elapseTime); counter.put(name, wu); } /** * 展示所有的结果 */ public static void dump() { for (String key : counter.keySet()) { System.out.println(counter.get(key).toString()); } counter.clear(); } /** * clone Watcher对象 */ @Override public Watcher clone() { Watcher watcher = null; try { watcher = (Watcher) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return watcher; } /** * 基于原型模式获取计时对象 */ public static Watcher getWatcher() { if (null == watcher) { watcher = new Watcher(); } return watcher.clone(); } /** * 监控单元 */ class WatchUnit { /** 监控单元 */ private String name; /** 监控内容执行次数 */ private int count = 0; /** 监控方法执行的时间 */ private Long totalElapseTime = 0L; WatchUnit(String name) { this.name = name; } public void add(long elapseTime) { this.count++; this.totalElapseTime += elapseTime; } @Override public String toString() { return name + "-------------" + "执行了" + count + "次;" + "共耗时" + totalElapseTime + "; 平均" + (totalElapseTime / count); } } } |
好了,就这样。
#########
发表评论