# dynamic-proxy **Repository Path**: wzk9261/dynamic-proxy ## Basic Information - **Project Name**: dynamic-proxy - **Description**: 基于 Maven 管理,测试 JDK 和 CGLIB 两种代理对接口或类方法的增强效果。 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-01-08 - **Last Updated**: 2024-06-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 准备工作 ## 代理简介 代理,简单来说,就是代替原有操作者,即委托者去处理一件事。在 Java 中代理一般分为两种,静态代理和动态代理,动态代理又分为 JDK 动态代理和 Cglib 动态代理。 ## 创建项目 创建一个简单的纯后端的 Maven 项目,在其中引入单元测试和 Cglib 相关依赖。 ```xml junit junit 4.12 test cglib cglib 3.3.0 ``` 注:本案例基于 JDK 1.8 # 静态代理 实现静态代理需要由显式地创建代理类。与动态代理不同的是,静态代理的 class 文件在编译之后,程序运行之前就已经存在了。 ## 接口 首先定义一个公共的 `Subject` 接口,该接口后续需要被委托类 `RealSubject` 和代理类 `ProxySubject` 共同实现。 ```java public interface Subject { void method(); } ``` ## 实现类 定义一个实现类 `RealSubject`,实现 `method` 方法。 ```java public class RealSubject implements Subject { @Override public void method() { System.out.println("real method implement"); } } ``` ## 代理类 定义一个代理类 `ProxySubject`,实现 `Subject` 接口,并使用构造器方法注入 `Subject` 接口。 ```java public class ProxySubject implements Subject { private Subject subject; public ProxySubject(Subject subject) { this.subject = subject; } @Override public void method() { before(); subject.method(); after(); } private void before() { System.out.println("static proxy: before method"); } private void after() { System.out.println("static proxy: after method"); } } ``` 构造器注入 `Subject` 接口,便于注入指定的实现类。在实现 `method` 方法时,调用委托者的 `method` 方法:`subject.method()`。before 和 after 方法分别为前置和后置的增强方法。 ## 单元测试 为静态代理创建相应的单元测试 ```java public class ProxySubjectTest { @Test public void method() { Subject subject = new RealSubject(); ProxySubject proxySubject = new ProxySubject(subject); proxySubject.method(); } } ``` 运行该测试方法,在控制台中观察输出。 ```java static proxy: before method real method implement static proxy: after method ``` # 动态代理 ## 准备工作 ### 接口和实现类 定义一个接口及其实现类,实现类会委托动态代理来对其实现的方法进行增强。 ```java public interface MyInterface { void methodA(); int methodB(); int methodC(int param1, int param2); } ``` ```java public class MyInterfaceImpl implements MyInterface { @Override public void methodA() { System.out.println("method A"); } @Override public int methodB() { System.out.println("method B"); return 0; } @Override public int methodC(int param1, int param2) { System.out.println("method C"); return param1 + param2; } } ``` ### 没有实现接口的类 定义一个没有实现接口的类。 ```java public class MyClass { public void methodA() { System.out.println("method A"); } public int methodB() { System.out.println("method B"); return 0; } public int methodC(int param1, int param2) { System.out.println("method C"); return param1 + param2; } } ``` ## JDK 动态代理 JDK 动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用 `InvocationHandler` 的 `invoke` 方法来处理。 ### 实现 ```java public class MyInvocationHandler implements InvocationHandler { private Object delegate; public MyInvocationHandler(Object delegate) { this.delegate = delegate; } public Object createJDKProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object result = method.invoke(delegate, args); after(); return result; } private void before() { System.out.println("jdk proxy: before method"); } private void after() { System.out.println("jdk proxy: after method"); } ``` 类似于静态代理,JDK 动态代理也是通过构造器注入委托类对象 `delegate`。 #### 创建动态代理对象 在 `createJDKProxy` 方法中,调用 `Proxy` 的 `newProxyInstance` 方法来创建一个 JDK 动态代理对象。 首先阅读 `newProxyInstance` 方法的源码注释: ```java /** * Returns an instance of a proxy class for the specified interfaces * that dispatches method invocations to the specified invocation * handler. * * @param loader the class loader to define the proxy class * @param interfaces the list of interfaces for the proxy class * to implement * @param h the invocation handler to dispatch method invocations to * @return a proxy instance with the specified invocation handler of a * proxy class that is defined by the specified class loader * and that implements the specified interfaces */ ``` 可知,`newProxyInstance` 的参数分别应该传入 - 代理类的类加载器。在本案例中,代理类即自定义的 `InvocationHandler` 接口实现类 `MyInvocationHandler`,所以传参为当前类对象的类加载器即可:`this.getClass().getClassLoader()`。 - 代理类要实现的接口数组类对象。这里传入委托类对象实现的接口类对象数组即可:`delegate.getClass().getInterfaces()`。 - 分发方法调用的 invocation handler。这里传入当前代理对象即可:`this` - 返回值为一个 JDK 代理实例。 #### 重写 invoke 方法 `invoke` 方法基于反射原理,当调用代理者中的接口方法时,会首先进入`invoke`方法中,从 `Object result = method.invoke(delegate, args)` 可以看出,JDK 动态代理基于反射原理调用委托者实现的接口方法,并获取其返回值。并按顺序执行前置和后置增强方法 `before` 和 `after`。 ### 单元测试 为 JDK 动态代理创建单元测试 ```java public class JDKProxyTest { private MyInterface myInterfaceJDKProxy; @Before public void setUp() { MyInterface myInterface = new MyInterfaceImpl(); MyInvocationHandler myInvocationHandler = new MyInvocationHandler(myInterface); myInterfaceJDKProxy = (MyInterface) myInvocationHandler.createJDKProxy(); } @Test public void methodA() { myInterfaceJDKProxy.methodA(); } @Test public void methodB() { assertEquals(0, myInterfaceJDKProxy.methodB()); } @Test public void methodC() { int param1 = 2; int param2 = 3; assertEquals(param1 + param2, myInterfaceJDKProxy.methodC(param1, param2)); } } ``` 在控制台中观察输出结果 - `methodA` ```java jdk proxy: before method method A jdk proxy: after method ``` - `methodB` ```java jdk proxy: before method method B jdk proxy: after method ``` - `methodC` ```java jdk proxy: before method method C jdk proxy: after method ``` ## Cglib 动态代理 Cglib 是一种动态代理方式,底层通过 ASM 产生字节码来完成动态代理,Cglib 与 JDK 动态代理相比,除了可以代理实现接口的类也可以代理非实现接口的类,通过 `FastClass` 类来避免了反射的使用。对 JDK 7 以前的版本来说,JDK 8 动态代理执行效率明显要比 Cglib 动态代理类效率差,JDK 8 即以后版本对 JDK 动态代理进行了相应的优化,这种差距就不那么明显了。但是要代理不实现接口的类来说,Cglib 就是一种必要选择。 ### 实现方式一:实现 `MethodInterceptor` 接口 ```java public class MyMethodInterceptor implements MethodInterceptor { private Object delegate; public MyMethodInterceptor(Object delegate) { this.delegate = delegate; } public Object createCglibProxy() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(delegate.getClass()); enhancer.setInterfaces(delegate.getClass().getInterfaces()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { before(); Object result = method.invoke(delegate, args); after(); return result; } private void before() { System.out.println("cglib proxy: before method"); } private void after() { System.out.println("cglib proxy: after method"); } } ``` 首先阅读一下 `setSuperclass` 方法的源码 ```java /** * Set the class which the generated class will extend. As a convenience, * if the supplied superclass is actually an interface, setInterfaces * will be called with the appropriate argument instead. * A non-interface argument must not be declared as final, and must have an * accessible constructor. * @param superclass class to extend or interface to implement * @see #setInterfaces(Class[]) */ public void setSuperclass(Class superclass) { if (superclass != null && superclass.isInterface()) { setInterfaces(new Class[]{ superclass }); } else if (superclass != null && superclass.equals(Object.class)) { // affects choice of ClassLoader this.superclass = null; } else { this.superclass = superclass; } } ``` 这里传入的参数 `superClass` 将会被生成的代理类继承,所以这里的 `superClass` 传入委托者(实现类)对应的 Class 对象。 再阅读一下 `setInterfaces` 的源码 ```java /** * Set the interfaces to implement. The Factory interface will * always be implemented regardless of what is specified here. * @param interfaces array of interfaces to implement, or null * @see Factory */ public void setInterfaces(Class[] interfaces) { this.interfaces = interfaces; } ``` 所以 `interfaces` 参数传入委托者实现的接口数组即可。这里不设置 `interfaces` 也没有关系,因为即使 `superClass` 参数为接口类型的话,在 `setSuperclass` 方法中会进行 `setInterfaces` 的工作。 `callback` 是 `Enhancer` 中能够拦截原方法并进行增强的关键,`MethodInterceptor` 接口是 `callback` 的子接口之一,可以对委托者的非 final 方法进行拦截,所以 `callback` 设置为当前 `MethodInterceptor` 的实现类对象,即 `this`;如果没有显式地创建 `MethodInterceptor` 的实现类,也可以隐式地创建 `MethodInterceptor` 的匿名内部类: ```java enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { before(); Object result = method.invoke(delegate, args); after(); return result; } }); ``` 在设置好 `superclass`、`interfaces`、`callback`后,调用 `enhancer.create()` 即可获取 Cglib 动态代理对象。 #### 单元测试 委托者没有实现接口的类的测试 ```java public class CglibProxy4ClassTest { private MyClass myClass; @Before public void setUp() { MyClass myInterfaceImpl = new MyClass(); MyMethodInterceptor myMethodInterceptor = new MyMethodInterceptor(myInterfaceImpl); myClass = (MyClass) myMethodInterceptor.createCglibProxy(); } @Test public void methodA() { myClass.methodA(); } @Test public void methodB() { assertEquals(0, myClass.methodB()); } @Test public void methodC() { int param1 = 2; int param2 = 3; assertEquals(param1 + param2, myClass.methodC(param1, param2)); } } ``` 委托者为实现了接口的类的测试 ```java public class CglibProxy4InterfaceTest { private MyInterface myInterfaceCglibProxy; @Before public void setUp() { MyInterface myInterface = new MyInterfaceImpl(); MyMethodInterceptor myMethodInterceptor = new MyMethodInterceptor(myInterface); myInterfaceCglibProxy = (MyInterface) myMethodInterceptor.createCglibProxy(); } @Test public void methodA() { myInterfaceCglibProxy.methodA(); } @Test public void methodB() { assertEquals(0, myInterfaceCglibProxy.methodB()); } @Test public void methodC() { int param1 = 2; int param2 = 3; assertEquals(param1 + param2, myInterfaceCglibProxy.methodC(param1, param2)); } } ``` 上述两个测试类的测试结果均为: - `methodA` ```java cglib proxy: before method method A cglib proxy: after method ``` - `methodB` ```java cglib proxy: before method method B cglib proxy: after method ``` - `methodC` ```java cglib proxy: before method method C cglib proxy: after method ``` ### 实现方式二:匿名内部类 方式二和方式一的原理是一样的,只是从形式上更简洁,因为使用了匿名内部类。 ```java public class CglibProxyFactory { public static Object createProxy(final Object delegate) { return Enhancer.create(delegate.getClass(), new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws InvocationTargetException, IllegalAccessException { before(); Object result = method.invoke(delegate, args); after(); return result; } private void before() { System.out.println("inner cglib proxy: before method"); } private void after() { System.out.println("inner cglib proxy: after method"); } }); } } ``` `createProxy` 方法中直接调用了 `Enhancer` 的 `create` 方法,其源码如下: ```java /** * Helper method to create an intercepted object. * For finer control over the generated instance, use a new instance of Enhancer * instead of this static method. * @param type class to extend or interface to implement * @param callback the callback to use for all methods */ public static Object create(Class type, Callback callback) { Enhancer e = new Enhancer(); e.setSuperclass(type); e.setCallback(callback); return e.create(); } ``` - `type` 参数传入的是代理对象将要继承的类或实现的接口,在本案例中即指代`MyClass`、`MyInterfaceImpl` 或 `MyInterface`,这里传参为 `delegate.getClass()`。 - `callback` 参数为所有非 final 方法对应的回调函数,即 `MethodInterceptor` 的实现类或其匿名内部类。这里简化为匿名内部类: ```java new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws InvocationTargetException, IllegalAccessException { before(); Object result = method.invoke(delegate, args); after(); return result; } private void before() { System.out.println("inner cglib proxy: before method"); } private void after() { System.out.println("inner cglib proxy: after method"); } } ``` #### 单元测试 同方式一的单元测试,创建一个 `CglibProxyFactory4ClassTest` 和 `CglibProxyFactory4InterfaceTest`,分别对没有实现接口的类和实现了接口的类做单元测试,测试结果也是断言通过,并且能够完成前置和后置方法中的打印。