其他分享
首页 > 其他分享> > mybatis0060-jdk动态代理

mybatis0060-jdk动态代理

作者:互联网

文章目录


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 调用过程

在这里插入图片描述

标签:mybatis0060,java,jdk,Object,代理,接口,MoveAble,new,public
来源: https://blog.csdn.net/wrongyao/article/details/90546409