mybatis0060-jdk动态代理

    xiaoxiao2023-10-19  164

    文章目录

    1. jdk动态代理是基于接口实现的2. 为接口生成实例对象2.1 MoveAble接口2.2 调用处理程序 MoveAbleHandler2.3 测试类2.4 结果 3. 执行过程分析4. 实现了接口的实例增加切面逻辑4.1 上述Move接口不变4.2 增加接口实现类 Tank4.3 修改代理处理程序 TankHandler4.4 测试4.5 结果4.6 调用过程 githup项目地址

    1. jdk动态代理是基于接口实现的

    jdk的动态代理是基于接口实现的,所以一定要有接口,它可以实现两个功能 1)为接口生成一个实例对象 2)为实现接口的实例对象加入切面逻辑;

    2. 为接口生成实例对象

    假设有个MoveAble接口,意为可移动的,通过jdk的动态代理可以生成实现这个接口的实例。

    2.1 MoveAble接口

    public interface MoveAble { void move(); }

    2.2 调用处理程序 MoveAbleHandler

    jdk生成的代理实例最终会调用这个类的invoke方法,相当于写在这个处理程序实现了原本应该由MoveAble实类实现的逻辑。

    public class MoveAbleHandler implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("这边是代理做的工作"); return null; } }

    2.3 测试类

    public class Test { public static void main(String[] args) throws Exception { // 第一个参数是类加载器,用来加载生成的代理类 // 第二个参数是代理类实现的接口 // 第三个参数是调用处理程序 MoveAble moveAble = (MoveAble) Proxy.newProxyInstance(MoveAble.class.getClassLoader(), new Class[]{MoveAble.class}, new MoveAbleHandler()); moveAble.move(); } }

    2.4 结果

    3. 执行过程分析

    Proxy.newProxyInstance()方法最终会通过native方法生成代理对象

    private static native Class<?> defineClass0(ClassLoader loader, String name,byte[] b, int off, int len);

    通过jdk的sum.misc.ProxyGenerator类可以查看生成的字节码文件,如下配置

    import java.io.File; import java.io.FileOutputStream; import java.lang.reflect.Proxy; /** * Created by rongyaowen * on 2019/5/23. */ public class Test { public static void main(String[] args) throws Exception { // 第一个参数是类加载器,用来加载生成的代理类 // 第二个参数是代理类实现的接口 // 第三个参数是调用处理程序 MoveAble moveAble = (MoveAble) Proxy.newProxyInstance(MoveAble.class.getClassLoader(), new Class[]{MoveAble.class}, new MoveAbleHandler()); moveAble.move(); byte[] bts = ProxyGenerator.generateProxyClass("$MoveAble", Tank.class.getInterfaces()); FileOutputStream fos = new FileOutputStream(new File("E:/$MoveAble.class")); fos.write(bts); fos.flush(); fos.close(); } }

    将生成的字节码拉入idea中可以看到如下内容

    import com.honor.proxy.MoveAble; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $MoveAble extends Proxy implements MoveAble { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $MoveAble(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue(); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void move() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } 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 int hashCode() throws { try { return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")}); m3 = Class.forName("com.honor.proxy.MoveAble").getMethod("move", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }

    注:重写了equals、hashCode和toString方法。重点看move方法,move方法通过反射调用了父类的invoke方法。

    return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();

    super.h是什么呢?跟进去一看是

    protected InvocationHandler h;

    h是什么时候赋值的呢,当生成的代理实例初始化时,会将InvocationHandler对象赋值给proxy

    public $MoveAble(InvocationHandler var1) throws { super(var1); }

    那么初始化实例的时候传入的是什么值呢

    return cons.newInstance(new Object[]{h});

    这个h就是newProxyInstance传入得第三个参数,是调用处理程序

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

    总结:通过newProxyInstance方法会生成一个实现了接口(第二个参数)的实例对象,这个对象实现了接口的方法,调用的是调用处理程序(第三个参数)的invoke方法。

    4. 实现了接口的实例增加切面逻辑

    4.1 上述Move接口不变

    4.2 增加接口实现类 Tank

    public class Tank implements MoveAble { public void move() { System.out.println("坦克移动。。。"); } }

    4.3 修改代理处理程序 TankHandler

    import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * Created by rongyaowen * on 2019/5/23. */ public class TankHandler implements InvocationHandler { // 传入实现了接口的实例,如这边的Tank实例 private MoveAble moveAble; public TankHandler(MoveAble moveAble) { this.moveAble = moveAble; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理开始"); Object object = method.invoke(moveAble, args); System.out.println("代理结束"); return object; } }

    4.4 测试

    import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; /** * Created by rongyaowen * on 2019/5/23. */ public class Test { public static void main(String[] args) throws Exception { Tank tank = new Tank(); InvocationHandler invocationHandler = new TankHandler(tank); MoveAble moveAble = (MoveAble) Proxy.newProxyInstance(MoveAble.class.getClassLoader(), new Class[]{MoveAble.class}, invocationHandler); moveAble.move(); } }

    4.5 结果

    注:这边在代理执行程序中还执行了代理类的方法

    Object object = method.invoke(moveAble, args);

    4.6 调用过程

    最新回复(0)