• 动态代理


    静态代理

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

    动态代理

    • 利用反射机制在运行时动态创建代理类
    • 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());
            }
        }
    }
    
    


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

  • 相关阅读:
    H3C-路由器密码恢复
    H3C-交换机密码恢复
    H3C-端口镜像
    [洛谷P4234]最小差值生成树
    [BZOJ4003]城池攻占
    [BZOJ1058]报表统计
    [BZOJ1584]Cleaning Up 打扫卫生
    [BZOJ3733]Iloczyn
    [HDU5709]Claris Loves Painting
    [BZOJ5109]大吉大利,晚上吃鸡!
  • 原文地址:https://www.cnblogs.com/wasitututu/p/13414957.html
Copyright © 2020-2023  润新知