动态代理

静态代理

  • 创建一个接口,然后创建目标类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个目标对象的引用,而后在代理类方法中调用该对象的方法

动态代理

  • 利用反射机制在运行时动态创建代理类
  • JDK动态代理使用步骤
    • 创建被代理的接口和类
    • 创建InvocationHandler接口的实现类,重写invoke方法,在invoke方法中实现代理逻辑
    • 通过Proxy的静态方法newProxyInstance( ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理对象
      • ClassLoaderloader 在哪个类里创建代理对象,就传入该类的类加载器
      • Class[] interfaces 代理类需要实现的接口
      • InvocationHandler 代理逻辑对象
    • 使用代理对象

实现原理

  • 在Proxy.newProxyInstanceProxy方法内部,会调用Generator类的generateProxyClass()方法来生成代理类的字节码,需要传入参数:代理类需要实现的接口数组
  • generateProxyClass()方法根据传入的接口数组,动态的成Class文件,包括字段和方法
  • JDK动态代理产生的代理类【继承】Proxy类,java是单继承,jdk动态代理是以实现接口的方式来执行的,并且【实现】接口数组中所有的接口
  • 代理类只有唯一构造方法,参数是InvocationHandlerd对象;构造方法内部逻辑是,把InvocationHandler对象传给父类Proxy类,也就是把InvocationHandler对象注入到Proxy类当中
  • 在创建InvocationHandlerd对象的时候,我们可以选择把目标对象注入到了InvocationHandler对象中(目标对象注入到InvocationHandler中,InvocationHandler对象注入到Proxy中)
  • 在使用代理类时,执行相应方法时,代理对象调用的是父类(Proxy类)中InvocationHandler对象的invoke方法,也就是我们之前重写的invoke方法:代理逻辑在此方法内
  • 在InvocationHandler对象的invoke方法内,除了代理逻辑,还可以调用目标对象的方法(在创建InvocationHandler对象时,目标对象注入到了InvocationHandler中)

示例demo

  • 目标接口
package Proxy;
public interface UserService {
    public String getName(String userId);
}
  • 目标实现类
package Proxy;
public class UserServiceImpl implements UserService{
    @Override
    public String getName(String userId) {
        System.out.println("hello");
        return userId;
    }
}
  • InvocationHandler实现类
package Proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

class MyInvocationHandler implements InvocationHandler {

    private Object object; //目标对象

    //通过构造方法,把目标对象进入进来
    public MyInvocationHandler(Object object){
        this.object = object;
    }

    //代理逻辑
     /***
     * @param proxy 生成的代理对象
     * @param method 代理对象中要执行的方法
     * @param args 方法参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前置代理逻辑");
        Object object = method.invoke(this.object, args);//除了代理逻辑,还可以选择调用目标对象的方法;this.object为注入的目标对象
        System.out.println("后置代理逻辑");
        return object;
    }
}

  • main方法测试
public class ZhuydProxy {
    public static void main(String[] args) throws IOException {
        UserService target = new UserServiceImpl(); //创建目标对象
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(target); //创建代理逻辑对象,目标对象注入到InvocationHandler中
        UserService userService = (UserService) Proxy.newProxyInstance(ZhuydProxy.class.getClassLoader(),
                target.getClass().getInterfaces(),
                myInvocationHandler
        );//通过JDK动态代理,创建代理对象
        userService.getName("123");//运用代理对象
    }
  • 运行结果
前置代理逻辑
hello
后置代理逻辑

查看动态代理生成的字节码文件到底张什么样

  • 通过ProxyGenerator.generateProxyClass( 生成的代理类名字 , 代理接口数组 ) 方法生成:代理字节码文件
  • 执行以下代码
byte[] bytes = ProxyGenerator.generateProxyClass("UserService$proxy",new Class[]{UserService.class});
Path path = new File("C:\\UserService$proxy.class").toPath();
Files.write(path,bytes);
  • 生成的字节码文件
import Proxy.UserService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class UserService$proxy extends Proxy implements UserService {
    private static Method m1;
    private static Method m2;
    private static Method m0;
    private static Method m3;

    public UserService$proxy(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 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);
        }
    }

    public final String getName(String var1) throws  {
        try {
            return (String)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m3 = Class.forName("Proxy.UserService").getMethod("getName", Class.forName("java.lang.String"));
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}



原创,如需转载请标明出处

posted @ 2020-08-01 18:56  队长别开枪 是我  阅读(322)  评论(7编辑  收藏  举报