Java中动态代理代理包括JDK动态代理和CGLIB动态代理。前者通过实现目标类的接口,和反射技术实现。后者不需要实现接口,而是通过继承目标类,并通过方法拦截技术实现。Spring的AOP技术则是集成了这两种动态代理。本文对两种代理的使用方法做一个简要介绍。
 代理模式
首先介绍下设计模式中的代理模式。代理模式是结构型模式的一种,要求代理对象实现被代理对象的接口,并持有被代理对象实例。外界只需要访问代理对象即可实现需要的功能。这种模式不会改变被代理对象的代码,但是又使其功能得到增强。
代理模式又分为两种,静态代理和动态代理。前者是在代码运行前就已存在代理类的字节码文件,相对扩展性较差。后者则是在运行时生成代理类。JDK中动态代理就是代理模式思想的体现。

 JDK动态代理
 特点
被代理对象要有实现接口,否则不能被代理。
生成的代理对象默认继承了Proxy。
 相关类
由于动态代理是基于反射,因此动态代理集成在java.lang.reflect包下。包括两个类:InvocationHandler 和 Proxy。前者提供了一个invoke方法,在这个方法里调用被代理对象的方法,并实现功能增强。后者提供了一个newProxyInstance静态方法,通过传入前者的实现,可以生成一个代理对象。
 步骤
 被代理类和接口
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | 
 
 public interface Star {
 
 void play();
 }
 
 
 
 
 public class Singer implements Star {
 
 public String name;
 
 public Singer(String name) {
 this.name = name;
 }
 
 @Override
 public void play() {
 System.out.println(name + " sing a new song!");
 }
 }
 
 | 
 重写invoke方法
实现 InvocationHandler 接口,需要引入被代理对象实例,在 invoke() 方法中调用需要代理的方法。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | public class MyInvocationHandler implements InvocationHandler {
 
 private Object object;
 
 public MyInvocationHandler(Object object) {
 this.object = object;
 }
 
 
 
 
 
 
 
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 System.out.println("proxy start");
 
 Object ret = method.invoke(this.object, args);
 System.out.println("proxy end");
 return ret;
 }
 }
 
 | 
 创建代理对象
通过Proxy.newProxyInstance()的方法,来创建代理对象
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | public class ProxyTest {public static void main(String[] args) {
 
 Singer singer = new Singer("Jay chou");
 
 InvocationHandler singerHandler = new MyInvocationHandler(singer);
 
 Object instance = Proxy.newProxyInstance(Singer.class.getClassLoader(), new Class[]{Star.class}, singerHandler);
 
 Star star1 = (Star)instance;
 
 star1.play();
 }
 }
 
 | 
 输出结果
可以看到,在play()的执行前后,执行了代理对象的逻辑
| 12
 3
 
 | proxy startJay chou sing a new song!
 proxy end
 
 | 
 源码分析
newProxyInstance方法源码
| 12
 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
 
 | 
 
 public class Proxy{
 
 @CallerSensitive
 public static Object newProxyInstance(ClassLoader loader,
 Class<?>[] interfaces,
 InvocationHandler h)
 throws IllegalArgumentException
 {
 Objects.requireNonNull(h);
 
 final Class<?>[] intfs = interfaces.clone();
 final SecurityManager sm = System.getSecurityManager();
 if (sm != null) {
 checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
 }
 
 
 Class<?> cl = getProxyClass0(loader, intfs);
 
 try {
 if (sm != null) {
 checkNewProxyPermission(Reflection.getCallerClass(), cl);
 }
 
 
 final Constructor<?> cons = cl.getConstructor(constructorParams);
 final InvocationHandler ih = h;
 if (!Modifier.isPublic(cl.getModifiers())) {
 AccessController.doPrivileged(new PrivilegedAction<Void>() {
 public Void run() {
 cons.setAccessible(true);
 return null;
 }
 });
 }
 
 
 return cons.newInstance(new Object[]{h});
 
 } catch (IllegalAccessException|InstantiationException e) {
 throw new InternalError(e.toString(), e);
 } catch (InvocationTargetException e) {
 Throwable t = e.getCause();
 if (t instanceof RuntimeException) {
 throw (RuntimeException) t;
 } else {
 throw new InternalError(t.toString(), t);
 }
 } catch (NoSuchMethodException e) {
 throw new InternalError(e.toString(), e);
 }
 }
 }
 
 | 
 CGLIB动态代理
 特点
CGLIB通过动态生成被代理类的子类,重写父类的所有非final方法,在子类中通过方法拦截技术拦截所有对父类方法的调用。与JDK动态代理相比,CGLIB速度更快,并且不要求被代理对象有实现接口。
 相关类
在net.sf.cglib.proxy包下,包括MethodInterceptor接口和Enhancer类。前者提供intercept方法实现对父类方法的拦截,后者通过create方法创建代理对象。
 步骤
 依赖导入
| 12
 3
 4
 5
 
 | <dependency><groupId>cglib</groupId>
 <artifactId>cglib</artifactId>
 <version>3.3.0</version>
 </dependency>
 
 | 
 被代理类
不要求有实现接口
| 12
 3
 4
 5
 6
 
 | public class Actress {
 public void play() {
 System.out.println("actor a queen!");
 }
 }
 
 | 
 重写intercept方法
cglib动态代理是基于方法拦截实现的,需要实现MethodInterceptor接口,重写intercept方法,在这里实现代理工作。
类似于InvocationHandler,区别在于,这里不需要引入被代理对象,由对父类的方法拦截完成。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;
 
 import java.lang.reflect.Method;
 
 public class MyMethodInterceptor implements MethodInterceptor {
 
 @Override
 public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
 System.out.println("method invoke before...");
 Object result = methodProxy.invokeSuper(obj, args);
 System.out.println("method invoke after...");
 return result;
 }
 }
 
 | 
 创建代理对象
创建代理对象并调用需要代理的方法
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | import net.sf.cglib.proxy.Enhancer;
 public class CglibProxyTest {
 public static void main(String[] args) {
 
 Enhancer enhancer = new Enhancer();
 
 enhancer.setSuperclass(Actress.class);
 
 enhancer.setCallback(new MyMethodInterceptor());
 
 Actress actress = (Actress)enhancer.create();
 
 actress.play();
 }
 }
 
 | 
 输出结果
| 12
 3
 
 | method invoke before...actor a queen!
 method invoke after...
 
 | 
 参考资料
- 面试必问系列之JDK动态代理
- CGLib动态代理