在写java代码的过程中经常会遇到需要打印一个方法的执行时间,如果在代码中直接写开始和结束时间,然后计算运行时间,这样感觉不太好,代码的耦合性太高,可以通过java的动态代理或者cglib 加上annotation(标注)来实现。
1.通过cglib代理打印当前方法的执行时间.
代码如下:
代理类:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
/**
* User: weichun.zhan
* Date: 12-10-25
* Time: 下午3:09
*/
public class ServiceProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Logger logger = LoggerFactory.getLogger(method.getDeclaringClass().getName());
Object result = null;
MethodRunTimeLog methodRunTimeLog = method.getAnnotation(MethodRunTimeLog.class);
if (methodRunTimeLog !=null && methodRunTimeLog.debug()) {
long start = System.currentTimeMillis();
result = methodProxy.invokeSuper(o, objects); //因为cglib是通过继承类来实现代理,so需调用invokesuper
long end = System.currentTimeMillis();
logger.info("Excute [{}] method took time [{}]ms.", method.getName(), (end - start));
} else {
result = methodProxy.invokeSuper(o, objects);
}
return result;
}
public Object createProxy(Class targetClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new ServiceProxy());
return enhancer.create();
}
}
调用类:
ServiceProxy test = new ServiceProxy();
MovieInfoServiceServiceImpl proxyTarget = (MovieInfoServiceServiceImpl)test.createProxy(MovieInfoServiceServiceImpl.class);
2.当然也可以通过jdk的动态代理来做,代码如下:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* User: weichun.zhan
* Date: 12-10-25
* Time: 下午6:03
*/
public class MovieInfoServiceProxy implements InvocationHandler {
private MovieInfoService impl;
public MovieInfoServiceProxy(MovieInfoService impl){
this.impl = impl;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Logger logger = LoggerFactory.getLogger(method.getDeclaringClass().getName());
Object result = null;
//获取调用方法的method对象,不能直接调用method,不知为什么还没仔细研究
MethodRunTimeLog methodRunTimeLog = impl.getClass().getMethod(method.getName(),method.getParameterTypes()).getAnnotation(MethodRunTimeLog.class);
if (methodRunTimeLog !=null && methodRunTimeLog.debug()) {
long start = System.currentTimeMillis();
result = method.invoke(impl, args);
long end = System.currentTimeMillis();
logger.info("Excute [{}] method took time [{}]ms.", method.getName(), (end - start));
} else {
result = method.invoke(impl, args);
}
return result;
}
}
调用代码:
MovieInfoService proxyTarget = (MovieInfoService) Proxy.newProxyInstance(MovieInfoService.class.getClassLoader(),
MovieInfoServiceImpl.class.getInterfaces(),new MovieInfoServiceProxy(new MovieInfoServiceImpl()));
return proxyTarget;
标注类:
import java.lang.annotation.*;
/**
* User: weichun.zhan
* Date: 12-10-25
* Time: 下午4:09
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MethodRunTimeLog {
boolean debug() default false;
}
ServiceImpl:
@MethodRunTimeLog(debug = true)
public List<MovieInfo> queryMovieInfos(Collection<String> cids) throws SQLException {
//具体的实现省略。。。。
}