`

JDK、CGLib动态代理

    博客分类:
  • AOP
阅读更多

  AOP,久违了!

  在AOP概念理解里面呢,学习了一下AOP的一些使用场合,这一篇呢,就来真正写一些示例,来学习这样的一个概念。

  在Spring AOP中呢,使用了动态代理技术在运行期织入增强的代码,我们都知道,JDK动态代理只提供了针对接口的代理,CGLib是对其的强有力补充,Spring AOP支持这两种代理方式。

  先来看一个一般的带有AOP概念色彩的示例程序,然后再在这个程序的基础上,使用上JDK动态代理技术和CGlib代理技术。

  1)

public class MethodPerformance {
	
	private static final Log log = LogFactory.getLog(MethodPerformance.class);
	
	private long begin;
	private long end;
	private String serviceMethod;//执行的方法
	
	public MethodPerformance(String serviceMethod){
		this.serviceMethod = serviceMethod;
		this.begin = System.currentTimeMillis();
	}
	
	public void printPerformance(){
		this.end = System.currentTimeMillis();
		log.info(serviceMethod+" processing take "+(end-begin)+" millisecond.");//方法执行的耗时
	}
}

 

   这个类完成的功能是这样的,就是来监测一个类中方法的执行耗时。这样一来,可以有效的监测程序的执行耗时,从而为程序的运行速度做一些参考。

  

   PerformanceMonitoring这个类呢,是对当前线程中运行的方法进行一个监测,实际上它充当了MethodPerformance的包装器了,begin方法接受执行的方法名,并记录方法执行的起始时间,end方法记录该方法的执行耗时,程序和逻辑都是相当的简单明了,现代码如下:

  

public class PerformanceMonitoring {
	
	private static final Log log = LogFactory.getLog(PerformanceMonitoring.class);
	
	private static ThreadLocal<MethodPerformance> performanceRecord =
		new ThreadLocal<MethodPerformance>();//当前线程中

	public static void begin(String method){
		log.info("begin monitoring...");
		MethodPerformance mp = new MethodPerformance(method);
		performanceRecord.set(mp);
	}
	
	public static void end(){
		log.info("end monitoring...");
		MethodPerformance mp = performanceRecord.get();//获取当前线程的对象实例
		mp.printPerformance();
	}
}

 

    现看一个service类,看看如何在方法中使用监测耗时,代码如下:

   

public class AopStudyService extends TestCase{
	
	private static final AopStudyService instance = new AopStudyService();
	
	public static AopStudyService getInstance(){
		return instance;
	}
	
	public void analogRemoveInfo() throws InterruptedException{
		PerformanceMonitoring.begin("analogRemoveInfo");//性能监测
		Thread.currentThread().sleep(200);//模拟该方法执行了200毫秒
		PerformanceMonitoring.end();//结束性能监测
	}
	
	public void testAnalogRemoveInfo() throws InterruptedException{
		instance.analogRemoveInfo();
	}
	
}

   analogRemoveInfo方法,模拟了一个耗时200ms的删除操作,通过PerformanceMonitoring.begin("analogRemoveInfo")来启动监测起始方法,方法执行完毕后,再调用PerformanceMonitoring.end()来结束监测,最后我们用JUnit Test运行,结果输出如下:

    

2010-11-21 21:11:21 org.aopStudy.common.PerformanceMonitoring begin
信息: begin monitoring...
2010-11-21 21:11:22 org.aopStudy.common.PerformanceMonitoring end
信息: end monitoring...
2010-11-21 21:11:22 org.aopStudy.common.MethodPerformance printPerformance
信息: analogRemoveInfo processing take 203 millisecond.

 通过这个例子,我想你肯定会对aop有一个感性的认识,但是这个程序有一个问题,我现在service里只有一个方法,如果service里的方法多了,那岂不是每个方法的执行开始之前我都要加入begin方法,方法执行完毕后调用end方法,这真的是件糟糕的事情,这无形中添加了我们写程序的负担,在编写复杂业务程序的时候,还得时刻提醒自己不忘记添加这两个方法,所以,必须改正它。

  2)通过JDK的反射机制重新实现这个逻辑代码如下:

    

public class PerformaceHandler implements InvocationHandler {

	private Object target;
	public PerformaceHandler(Object target){
		this.target = target;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		PerformanceMonitoring.begin(target.getClass().getName()+"."+method.getName());
		Object obj = method.invoke(target, args);//通过反射调用方法
		PerformanceMonitoring.end();
		return obj;
	}

}

     这是个代理实例调用处理程序的一个典型使用方式,通过指定一个目标对象,然后通过代理实例调用方法时,将其指派到它的调用处理程序的 invoke 方法。invoke方法在通过反射调用方法的前后添加了如上的监测代码,现来看看目标对象

   

public class JdkReflectService extends TestCase implements IJdkReflectService{
	private static final JdkReflectService instance = new JdkReflectService();
	
	public static JdkReflectService getInstance(){
		return instance;
	}
	
	public void analogRemoveInfo() throws InterruptedException{
//		PerformanceMonitoring.begin("analogRemoveInfo");//性能监测
		Thread.currentThread().sleep(200);//模拟该方法执行了200毫秒
//		PerformanceMonitoring.end();//结束性能监测
	}
	
	public void testAnalogRemoveInfo() throws InterruptedException{
		IJdkReflectService target = JdkReflectService.getInstance();
		PerformaceHandler handler = new PerformaceHandler(target);
		IJdkReflectService proxy = (IJdkReflectService) Proxy.newProxyInstance(
				target.getClass().getClassLoader(), target.getClass()
						.getInterfaces(), handler);
		proxy.analogRemoveInfo();
	}
}

  可以看到在analogRemoveInfo() 方法中注释掉了如上的性能监测代码,通过JUnit Test运行可得到如上的结果。我们说过,JDK的代理是针对接口的,也就是说,即便像我们这个service中只有一个方法,为了使用JDK动态代理,我们还不得不多写一个service的接口,这下悲剧了,我们不禁会想:何必把简单的事情搞复杂呢?!OK,CGLib派上用场了:

   3)

  

public class CglibProxy extends TestCase implements MethodInterceptor{
	
	private Enhancer enhancer  = new Enhancer();
	public Object getProxy(Class clz){
		enhancer.setSuperclass(clz);//设置需要创建子类的类
		enhancer.setCallback(this);
		return enhancer.create();//返回创建的子类对象
	}
	
	/**
	 * 拦截所有目录类方法
	 * @param arg0 目录类实例
	 * @param arg1 目标类方法的反射对象
	 * @param arg2 方法参数
	 * @param arg3 代理实例
	 * */
	@Override
	public Object intercept(Object arg0, Method arg1, Object[] arg2,
			MethodProxy arg3) throws Throwable {
		PerformanceMonitoring.begin(arg0.getClass().getName()+"."+arg1.getName());
		Object result = arg3.invokeSuper(arg0, arg2);
		PerformanceMonitoring.end();
		return result;
	}
	
	public void testCglibProxy() throws InterruptedException{
		CglibProxy proxy = new CglibProxy();
		CglibReflectService service = (CglibReflectService) proxy.getProxy(CglibReflectService.class);
		service.analogRemoveInfo();
	}
}

    可以看到,通过实现MethodInterceptor接口的唯一方法intercept,在intercept这个方法里加入耗时监测,通过getProxy方法获取代理实例,再调用对应的方法即可,具体的代码可参见附件,也请各位多多指正,共同进步。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics