java 动态代理与反射

double

使用 java 反射进行动态代理,java 的反射使用到了代理模式,所谓的代理模式就是在原有的服务上多加一个占位,通过这个占位去控制服务的访问,对应 javascript 的 (bind、get || set、proxy) 相似。

为什么要使用代理模式?
一方面可以控制如何访问真正的服务对象,提供额外服务和进行追踪,另一方面有机会通过重写一些类来满足特定的需求。

一、JDK动态代理

反射代理需要实现 java.lang.reflect.InvocationHandler 接口。
① 编写代理类

public class HelloServiceProxy implements InvocationHandler { /** * 真实服务对象 */ private Object target; /** * 绑定委托对象并返回一个代理类 * @param target * @return */ public Object bind(Object target) { this.target = target; /** * 这个代理对象有三个参数, * 第一个参数是类加载器, * 第二个参数是接口(代理对象挂在哪个接口下) * 第三个参数 this 代表当前 HelloServiceProxy,另外一种意思是使用 HelloService 的代理方法作为对象的代理执行者。 */ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } /** * 通过代理对象调用方法首先进入这个方法 * @param proxy * @param method * @param args * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.err.println("####### 我是 JDK 动态代理 #######"); Object result; // 反射方法前调用 System.err.println("我准备说hello。"); // 执行方法,相当于调用 HelloServiceImpl 类的 sayHello 方法 result = method.invoke(target, args); // 反射方法后调用 System.out.println("我说过 hello 了"); return result; } }

② 编写接口

public interface HelloService { String sayHello(); }

③ 编写实现类

public class HelloServiceImpl implements HelloService { @Override public String sayHello() { return "2333e"; } }

④ 调用

public static void main(String[] args) { HelloServiceProxy helloHandler = new HelloServiceProxy(); HelloService proxy = (HelloService)helloHandler.bind(new HelloServiceImpl()); proxy.sayHello(); }

最后在idea控制台可以看到

####### 我是 JDK 动态代理 #######
我准备说hello
我说过 hello 了

二、CGLIB 动态代理

JDK 提供的动态代理存在一个缺陷,就是你必须提供接口才可以使用,为了克服这个缺陷,我们可以使用开源框架–CGLIB,它是一种流行的动态代理,我们需要实现 org.springframework.cglib.proxy.MethodInterceptor 接口的 intercept 方法。HelloService 接口和 HelloServiceImpl 实现类保持不变。

代码实现逻辑

public class HelloServiceProxy2 implements MethodInterceptor { private Object target; /** * 创建代理对象 * * @param target * @return */ public Object getInstance(Object target) { this.target = target; /** * Enhancer: 增强器 * 它是一个字节码增强器,可以用来为无接口的类创建代理,功能与 java 自带的 Proxy 类挺相似的,会根据某个给定的类创建子类 * 并且所有非 final 的方法都带有回调钩子。 */ Enhancer enhancer = new Enhancer(); // 获取代理对象的类 enhancer.setSuperclass(this.target.getClass()); // 回调方法 enhancer.setCallback(this); return enhancer.create(); } /** * 回调方法 * @param o * @param method * @param objects * @param methodProxy * @return * @throws Throwable */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.err.println("########## 我是 CGLIB 的动态代理 #########"); // 反射方法前调用 System.err.println("我准备说 hello"); Object returnObj = methodProxy.invokeSuper(o, objects); // 反射方法后调用 System.err.println("我说过 hello 了"); return returnObj; } }

调用

public static void main(String[] args) { HelloServiceProxy2 helloServiceProxy2 = new HelloServiceProxy2(); HelloService helloService = (HelloService) helloServiceProxy2.getInstance(new HelloServiceImpl()); String result = helloService.sayHello(); System.out.println(result); }

参考阅读