Loading... # 浅谈java动态代理 ## 介绍 我们之前的文章提到过静态代理,也就是[代理模式](https://www.princelei.club/archives/119.html),它可以通过对某个对象的包装来实现修改对象方法执行前后的逻辑,或者修改返回值类型,但是这种静态代理方式需要继承接口,并且需要指定对象的传入,显然不够灵活,因此我们需要运用动态代理。 ## 基于接口的动态代理(Proxy) Proxy是jdk提供的一套动态代理,基于反射实现。 ### 示例 首先创建一个动物接口,有跑和叫两种方法。 ``` public interface Animal { void run(); void call(); } ``` Dog类实现Animal接口 ``` public class Dog implements Animal { @Override public void run() { System.out.println("狗跑"); } @Override public void call() { System.out.println("wangwangwang"); } } ``` 客户端调用 ``` public class MainClass { public static void main(String[] args) { Animal animal = new Dog(); Animal animalProxy = (Animal) Proxy.newProxyInstance(Dog.class.getClassLoader(), Dog.class.getInterfaces(), (proxy, method, args1) -> { System.out.println(method.getName() + "执行前"); Object invoke = method.invoke(animal, args1); System.out.println(method.getName() + "执行后"); return invoke; }); animalProxy.run(); System.out.println("----------"); animalProxy.call(); } } ``` 输出: ``` run执行前 狗跑 run执行后 ---------- call执行前 wangwangwang call执行后 ``` 可以明显看到,我们在方法的前后加上了自己的执行逻辑,Proxy是java.lang.reflect包提供的一个代理类,newProxyInstance()方法创建一个Proxy实例需要传入被代理类的ClassLoader和实现的所有接口,还有一个方法拦截器,方法拦截器参数为,proxy代理对象,method方法,args1方法参数,通过需要传入所有实现接口可知,该代理模式是基于接口实现的,但是我们实际生产环境不可能所有类都继承了接口,所以该代理模式有局限性。 ## 基于类的代理(cglib) 如果我们要代理的类没有实现接口,那么我们代理它的方法就是,创建一个类,继承要代理的类。由于是动态代理,我们肯定不能手动继承,因此cglib需要用到ASM来实现。 ### 何为ASM? ASM 是一个 Java 字节码操控框架。它能够以二进制形式修改已有类或者动态生成类。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。 我们可以用ASM动态生成一个被代理类的儿子。 ### 示例 现在我们有一个鸭子类,有跑和叫两个方法,注意,它没有实现任何接口。 ``` public class Duck{ public void run() { System.out.println("鸭子跑"); } public void call() { System.out.println("gagaga"); } } ``` 我们创建一个CgLibFactory工厂类,该工厂需要实现MethodInterceptor接口。 ``` public class CgLibFactory implements MethodInterceptor { private Object target; //构造器初始化被代理对象 public CgLibFactory(Object target) { this.target = target; } public CgLibFactory() { } public Object createProxy() { //增强器 Enhancer enhancer = new Enhancer(); //设置父类 enhancer.setSuperclass(target.getClass()); //设置回调,返回给intercept方法 enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println(method.getName() + "执行前"); method.invoke(target, objects); System.out.println(method.getName() + "执行后"); return null; } } ``` 客户端调用 创建一个鸭子对象,创建一个CgLibFactory工厂对象,通过构造器传入被代理的鸭子对象,然后调用createProxy()方法交给增强器去处理。增强器处理完会通过回调,调用intercept()方法。 ``` public static void main(String[] args) { Duck duck = new Duck(); CgLibFactory factory = new CgLibFactory(duck); Duck duckProxy = (Duck) factory.createProxy(); duckProxy.run(); System.out.println("----------"); duckProxy.call(); } ``` 输出: ``` run执行前 鸭子跑 run执行后 ---------- call执行前 gagaga call执行后 ``` 代理成功! Last modification:June 11th, 2020 at 06:18 pm © 允许规范转载