在运行时,通过某种方法动态生成代理类.class文件,比较常见技术就是JAVA动态代理和Cglib代理。
必须定义一个接口
public interface Animal { void eat(String food); } 复制代码
实现类Cat
public class Cat implements Animal { @Override public void eat(String food) { System.out.println(Cat.class.getSimpleName()+" eat:"+food); } } 复制代码
实现类Dog
public class Dog implements Animal { @Override public void eat(String food) { System.out.println(Dog.class.getSimpleName()+" eat:"+food); } } 复制代码
public class AnimalHandler implements InvocationHandler { private Animal target; public AnimalHandler(Animal target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); //这里可以修改参数 StringBuilder stringBuilder=new StringBuilder(); for (int i = 0; i < args.length; i++) { stringBuilder.append("param"+(i+1)+":"+args[i]).append(","); } if (stringBuilder.length()>1){ System.out.println(stringBuilder.subSequence(0,stringBuilder.length()-1)); } System.out.println("method:"+method.getName()); Object ret=method.invoke(target,args); after(); return ret; } /** * 方法执行前 */ private void before() { System.out.println("方法执行前 !"); } /** * 方法执行后 */ private void after() { System.out.println("方法执行后"); } } 复制代码
测试生成代理类
public static void main(String[] args) { System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); Animal cat = new Cat(); //找到代理对象 Animal catProxy = (Animal) Proxy.newProxyInstance(Cat.class.getClassLoader(), new Class[]{Animal.class}, new AnimalHandler(cat)); System.out.println(catProxy.getClass().getSimpleName()); catProxy.eat("猫粮"); Animal dog = new Dog(); Animal dogProxy = (Animal) Proxy.newProxyInstance(Dog.class.getClassLoader(), new Class[]{Animal.class}, new AnimalHandler(dog)); System.out.println(dogProxy.getClass().getSimpleName()); dogProxy.eat("狗粮"); } 复制代码
输出结果:
$Proxy0 方法执行前 ! param1:猫粮 method:eat Cat eat:猫粮 方法执行后 $Proxy0 方法执行前 ! param1:狗粮 method:eat Dog eat:狗粮 方法执行后 复制代码
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"),这句话会在本地生成代理类文件。
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.sun.proxy; import com.yuntian.firstspringboot.proxy.Animal; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements Animal { private static Method m1; private static Method m2; private static Method m3; private static Method m0; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void eat(String var1) throws { try { super.h.invoke(this, m3, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m3 = Class.forName("com.yuntian.firstspringboot.proxy.Animal").getMethod("eat", Class.forName("java.lang.String")); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } } 复制代码
Proxy.newProxyInstance(Cat.class.getClassLoader(), new Class[]{Animal.class}, new AnimalHandler(cat)); 复制代码
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); Class<?> cl = getProxyClass0(loader, intfs); 复制代码
分析这句代码和上面执行流程,参数有类加载器classloader、接口类、Handler实现类。源码分析,可以晓得生成一个代理类,然后反射获取接口的全部方法,并实现方法,再通过h.invoke()方法,调用原对象的方法。
这里可以定义接口或者类
public abstract class AbstartAnimal { public abstract void eat(String food); } 复制代码
public class CatTest extends AbstartAnimal { @Override public void eat(String food) { System.out.println(CatTest.class.getSimpleName()+" eat:"+food); } } 复制代码
public class DogTest extends AbstartAnimal { @Override public void eat(String food) { System.out.println(DogTest.class.getSimpleName()+" eat:"+food); } } 复制代码
定义方法拦截器
import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class AbstratAnimalInterceptor implements MethodInterceptor { /** * 被增强的类 */ private AbstartAnimal target; public AbstratAnimalInterceptor(AbstartAnimal target) { super(); this.target = target; } /** * 用来产生代理对象 */ public Object createProxy() { // 增强类 Enhancer enhancer = new Enhancer(); // 设置增强类的回调方法 enhancer.setCallback(this); //设置代理类的父类 enhancer.setSuperclass(AbstartAnimal.class); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { before(); Object ret = method.invoke(target, objects); after(); return ret; } /** * 方法执行前 */ private void before() { System.out.println("方法执行前 !"); } /** * 方法执行后 */ private void after() { System.out.println("方法执行后"); } } 复制代码
测试方法:
@Test public void testcglibProxy() { AbstartAnimal cat = new CatTest(); AbstratAnimalInterceptor interceptorCat = new AbstratAnimalInterceptor(cat); AbstartAnimal catProxy = (AbstartAnimal) interceptorCat.createProxy(); catProxy.eat("猫粮"); AbstartAnimal dog = new DogTest(); AbstratAnimalInterceptor interceptorDog = new AbstratAnimalInterceptor(dog); AbstartAnimal dogProxy = (AbstartAnimal) interceptorDog.createProxy(); dogProxy.eat("狗粮"); } 复制代码
输出:
方法执行前 ! CatTest eat:猫粮 方法执行后 方法执行前 ! DogTest eat:狗粮 方法执行后 复制代码
比较因素 | JAVA动态代理 | Cglib代理 |
---|---|---|
使用方便 | 方便 | 方便 |
生成方式 | 动态字节码 | 动态字节码 |
生成效率 | 13ms/个 | 217ms/个 |
运行效率 | 2224 ms, 634,022 t/s | 1123 ms, 1,255,623 t/s |
在Spring中使用代理技术只有JAVA动态代理和Cglib代理,此外生成代理类技术还有JAVAASSIST和ASM。