AOP的底层实现-CGLIB动态代理和JDK动态代理

原创 2013年10月20日 19:53:52
        AOP是目前Spring框架中的核心之一,在应用中具有非常重要的作用,也是Spring其他组件的基础。它是一种面向切面编程的思想。关于AOP的基础知识,相信多数童鞋都已经了如指掌,我们就略过这部分,来讲解下AOP的核心功能的底层实现机制:如何用动态代理来实现切面拦截。
        AOP的拦截功能是由java中的动态代理来实现的。说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执行。不同的切入时机对应不同的Interceptor的种类,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。
        那么动态代理是如何实现将切面逻辑(advise)织入到目标类方法中去的呢?下面我们就来详细介绍并实现AOP中用到的两种动态代理。
        AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理。两种方法同时存在,各有优劣。jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。
一、jdk动态代理实现AOP拦截(代码中的关键地方都添加了注释)

1、为目标类(target)定义统一的接口类Service,这个是jdk动态代理必须的前提。
package jdkproxy;

/**
 * 该类是所有被代理类的接口类,jdk实现的代理要求被代理类基于统一的接口
 * 
 * @author typ
 * 
 */
public interface Service {
	/**
	 * add方法
	 */
	public void add();

	/**
	 * update方法
	 */
	public void update();
}
2、目标类AService,我们的实验目标就是在AService中add和update方法的前后实现拦截,加入自定义切面逻辑advise
package jdkproxy;

/**
 * 被代理类,即目标类target
 * 
 * @author typ
 * 
 */
public class AService implements Service {
	/*
	 * (non-Javadoc)
	 * 
	 * @see jdkproxy.Service#add()
	 */
	public void add() {
		System.out.println("AService add>>>>>>>>>>>>>>>>>>");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see jdkproxy.Service#update()
	 */
	public void update() {
		System.out.println("AService update>>>>>>>>>>>>>>>");
	}
}
3、实现动态代理类MyInvocationHandler,实现InvocationHandler接口,并且实现接口中的invoke方法。仔细看invoke方法,就是在该方法中加入切面逻辑的。目标类方法的执行是由mehod.invoke(target,args)这条语句完成。
package jdkproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @author typ
 *
 */
public class MyInvocationHandler implements InvocationHandler {
	private Object target;

	MyInvocationHandler() {
		super();
	}

	MyInvocationHandler(Object target) {
		super();
		this.target = target;
	}

	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		// 程序执行前加入逻辑,MethodBeforeAdviceInterceptor
		System.out.println("before-----------------------------");
		// 程序执行
		Object result = method.invoke(target, args);
		// 程序执行后加入逻辑,MethodAfterAdviceInterceptor
		System.out.println("after------------------------------");
		return result;
	}

}
4、测试类,其中增强的目标对象是由Proxy.newProxyInstance(aService.getClass().getClassLoader(), aService.getClass().getInterfaces(), handler);来生成的。
package jdkproxy;

import java.lang.reflect.Proxy;

/**
 * @author typ
 *
 */
public class Test {
	public static void main(String[] args) {
		Service aService = new AService();
		MyInvocationHandler handler = new MyInvocationHandler(aService);
		// Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例
		Service aServiceProxy = (Service) Proxy.newProxyInstance(aService
				.getClass().getClassLoader(), aService.getClass()
				.getInterfaces(), handler);
		// 由动态生成的代理对象来aServiceProxy 代理执行程序,其中aServiceProxy 符合Service接口
		aServiceProxy.add();
		System.out.println();
		aServiceProxy.update();
		// 以下是对B的代理
		// Service bService = new BService();
		// MyInvocationHandler handler = new MyInvocationHandler(bService);
		// Service bServiceProxy = (Service) Proxy.newProxyInstance(bService
		// .getClass().getClassLoader(), bService.getClass()
		// .getInterfaces(), handler);
		// bServiceProxy.add();
		// System.out.println();
		// bServiceProxy.update();
	}
}
自此,jdk动态代理来实现AOP拦截机制的代码已经实现,下面我们看一下拦截的结果,程序输出结果如下:
before-----------------------------
AService add>>>>>>>>>>>>>>>>>>
after------------------------------
before-----------------------------
AService update>>>>>>>>>>>>>>>
after------------------------------
可以看到,在目标类AService的add和update方法前后已经加入了自定义的切面逻辑,AOP拦截机制生效了。

二、cglib动态代理实现AOP拦截(代码中的关键地方都添加了注释

1、目标类,cglib不需要定义目标类的统一接口
package cglibproxy;

/**
 * 被代理类,即目标对象target
 * 
 * @author typ
 * 
 */
public class Base {
	/**
	 * 一个模拟的add方法
	 */
	public void add() {
		System.out.println("add ------------");
	}
}
2、实现动态代理类CglibProxy,需要实现MethodInterceptor接口,实现intercept方法。该代理中在add方法前后加入了自定义的切面逻辑,目标类add方法执行语句为proxy.invokeSuper(object, args);
package cglibproxy;

import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * 此为代理类,用于在pointcut处添加advise
 * 
 * @author typ
 * 
 */
public class CglibProxy implements MethodInterceptor {

	public Object intercept(Object object, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		// 添加切面逻辑(advise),此处是在目标类代码执行之前,即为MethodBeforeAdviceInterceptor。
		System.out.println("before-------------");
		// 执行目标类add方法
		proxy.invokeSuper(object, args);
		// 添加切面逻辑(advise),此处是在目标类代码执行之后,即为MethodAfterAdviceInterceptor。
		System.out.println("after--------------");
		return null;
	}

}
3、获取增强的目标类的工厂Factory,其中增强的方法类对象是有Enhancer来实现的,代码如下所示:
package cglibproxy;

import net.sf.cglib.proxy.Enhancer;

/**
 * 工厂类,生成增强过的目标类(已加入切入逻辑)
 * 
 * @author typ
 * 
 */
public class Factory {
	/**
	 * 获得增强之后的目标类,即添加了切入逻辑advice之后的目标类
	 * 
	 * @param proxy
	 * @return
	 */
	public static Base getInstance(CglibProxy proxy) {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(Base.class);
		//回调方法的参数为代理类对象CglibProxy,最后增强目标类调用的是代理类对象CglibProxy中的intercept方法
		enhancer.setCallback(proxy);
		// 此刻,base不是单纯的目标类,而是增强过的目标类
		Base base = (Base) enhancer.create();
		return base;
	}
}
4、测试类
package cglibproxy;

/**
 * @author typ
 *
 */
public class Test {
	public static void main(String[] args) {
		CglibProxy proxy = new CglibProxy();
		// base为生成的增强过的目标类
		Base base = Factory.getInstance(proxy);
		base.add();
	}
}
自此,cglib动态代理实现的AOP拦截机制已经基本实现,下面我们来看一下拦截的效果如何,程序执行结果如下:
before-------------
add ------------
after--------------
可以看到,在目标类Base的add方法前后已经加入了自定义的切面逻辑,AOP拦截机制生效了。
此外,需要说明一下的是,cglib动态代理用到了第三方类库,需要在项目中引入两个jar包:cglib.jar和asm.jar。稍后会在csdn资源中上传这两个jar包。免积分的啊。

总之,AOP的核心机制和基本功能已经能够通过动态代理来实现了,至于AOP中,如何从配置文档中得到目标类target、advisor的bean,如何判断拦截器类型等问题,就借助于Spring中另一个核心IOC来解决了,后续会有IOC的核心实现机制讲解。

CGLIB介绍与原理

CGLIB介绍与原理(部分节选自网络) 一、什么是CGLIB? CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动...
  • zghwaicsdn
  • zghwaicsdn
  • 2016年03月22日 18:58
  • 28930

CGLIB(Code Generation Library)详解

什么是CGLIB CGLIB是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架(Spring、dynaop)中,用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架,同样使用...
  • danchu
  • danchu
  • 2017年04月19日 10:55
  • 5103

CGLIB

1、CGLIB    官网:http://cglib.sourceforge.net                CGLIB是一个强大的高性能的代码生成包。它被许多AOP的框架(例如Spring ...
  • u010150082
  • u010150082
  • 2013年09月02日 13:16
  • 2495

CGlib 入门

CGlib 入门cglib github地址链接。项目maven构建: cglib cglib 3.1 项目gradle构建:dependencies { compi...
  • rodbate
  • rodbate
  • 2015年12月30日 13:45
  • 581

cglib动态代理技术

一、原理       代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。JDK的动态代理用起...
  • u011130752
  • u011130752
  • 2016年07月27日 14:09
  • 891

谈谈java的代理模式认识 三————CGLIB代理

接着上篇博客的代理模式,我们继续,上篇博客介绍了JDK的动态代理,但是JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,这样就存在一定的局限性。对于这种情况,我...
  • wangyongxia921
  • wangyongxia921
  • 2015年05月29日 22:01
  • 2262

动态代理proxy与CGLib的区别

静态代理与动态代理 代理分为静态代理和动态代理    按照代理创建的时期,可以分为动态代理和静态代理:  静态代理:由程序员或者自动生成工具生成代理类,然后进行代理类的编译和运行。在代理类、委托...
  • zhengchao1991
  • zhengchao1991
  • 2016年12月09日 11:01
  • 608

Spring的两种代理JDK和CGLIB的区别浅谈

一、原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。 而cglib动态代理是利用asm开源包,对代理对象类的cla...
  • u013126379
  • u013126379
  • 2016年08月04日 17:39
  • 18920

支撑Spring的基础技术:反射,动态代理,cglib等

1.类名.class, class.forName(), getClass()区别 1:Class cl=A.class;   JVM将使用类A的类装载器, 将类A装入内存(前提是:类A还没有装入内存...
  • unix21
  • unix21
  • 2016年03月01日 22:50
  • 1577

cglib动态代理介绍(一)

一、原理       代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。JDK的动态代理用起来非...
  • xiaohai0504
  • xiaohai0504
  • 2011年09月29日 13:43
  • 49164
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:AOP的底层实现-CGLIB动态代理和JDK动态代理
举报原因:
原因补充:

(最多只允许输入30个字)