• Java动态代理


    Java实现动态代理,主要需要三个角色

    1、被代理的接口以及代理接口的具体实现类

    interface Interface {
        void sayHello();
    
        void sayBye();
    }
    class InterfaceImpl implements Interface {
    
        @Override
        public void sayHello() {
            System.out.println("hello");
        }
    
        @Override
        public void sayBye() {
            System.out.println("bye");
        }
    }

    2、用于处理具体代理逻辑的InvocationHandler

    class ProxyInvocationHandler implements InvocationHandler {
    
        private Object instance;
    
        public ProxyInvocationHandler(Object instance) {
            this.instance = instance;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("start proxy for method " + method.getName());
            method.invoke(instance, args);
            System.out.println("end proxy for method " + method.getName());
            return null;
        }
    }

    3、Proxy工厂类

    Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, invocationHandler);

    具体调用方法如下

    public class ProxyDemo {
    
        public static void main(String[] args) {
            System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
            InterfaceImpl target = new InterfaceImpl();
            ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler(target);
            Interface i = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, invocationHandler);
            i.sayHello();
            i.sayBye();
        }
    
    }

    Java动态代理的实现方式是,根据Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)的前两个参数动态生成代理类,并InvocationHandler做为构造参数,传给生成的Proxy实例

    可以通过配置System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");设置将生成的class类写入文件,代理类由sun.misc.ProxyGenerator生成

    Proxy生成的代理类反编译后的代码如下

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //

    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 Interface {
    private static Method m3;
    private static Method m1;
    private static Method m4;
    private static Method m0;
    private static Method m2;

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

    public final void sayHello() throws {
    try {
    super.h.invoke(this, m3, (Object[])null);
    } catch (RuntimeException | Error var2) {
    throw var2;
    } catch (Throwable var3) {
    throw new UndeclaredThrowableException(var3);
    }
    }

    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 void sayBye() throws {
    try {
    super.h.invoke(this, m4, (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 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);
    }
    }

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

    Proxy在加载代理类时,使用了两层的缓存,一层是基于classloader的缓存,缓存了不同的classloader,而基于不同的classloader,会缓存已经生成的代理类,缓存的key基于newInstance方法中传入的interfaces而生成

    生成Key的逻辑如下

            public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
                switch (interfaces.length) {
                    case 1: return new Key1(interfaces[0]); // the most frequent
                    case 2: return new Key2(interfaces[0], interfaces[1]);
                    case 0: return key0;
                    default: return new KeyX(interfaces);
                }
            }

    而Key1,Key2,KeyX中则重写了对应的equals方法来区分是否相同

    此外,如果在代理的接口中,存在内部接口,即不是申明为public的接口,那么Proxy生成的类的包名会是内部接口所处的包,如果实现的接口全部是public的,则会使用默认包名com.sun.proxy,同时生成的类名为Proxy+序列号,序列号由AtomicLong生成

  • 相关阅读:
    javaScript事件(二)事件处理程序
    【前端】模糊图片
    【前端】js转码
    【翻译】Sencha Touch2.4 The Layout System 布局
    Sencha Touch 2.4 callParent() 用法
    2015 WEB前端学习路线图
    Nodejs Express 4.X 中文API 4--- Router篇
    Nodejs Express 4.X 中文API 3--- Response篇
    Nodejs Express 4.X 中文API 2--- Request篇
    Nodejs Express 4.X 中文API 1--- Application篇
  • 原文地址:https://www.cnblogs.com/yytxdy/p/12218234.html
Copyright © 2020-2023  润新知