• # Java中的代理类


    public class Proxy extends Object implements Serializable
    Proxy类提供了用于创建动态代理类和实例的静态方法,它同时也是这些方法所创建的实例的超类。
    要创建某个接口Foo的代理:

    InvocationHandler handler = new MyInvocationHandler();
    Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(),Foo.class);
    Foo f = proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);
    // 更简单的方式
    Foo f = (Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class<?>[]{Foo.class},handler);
    

    一个动态代理类(下面简称为代理类)是这样一个类:它在创建时,实现了在运行时指定的一系列接口。一个代理接口是一个被代理类实现的接口。一个代理实例就是代理类的实例。每一个代理实例都有一个关联的调用处理器对象(invocation handler),该对象实现了InvocationHandler接口。在该代理对象上调用一个代理接口的方法时,会被分发到该实例的调用处理器的invoke方法上,同时传给该方法的还有代理实例,一个java.lang.reflect.Method对象,该对象决定要调用的方法,以及一个对象数组包含调用参数。调用处理器会适当的处理被编码的方法,并且该方法的返回值会作为该代理实例在该方法调用上的结果被返回。
    一个代理类有如下属性:

    • 如果所有的代理接口都是public,那么代理类就是 public,final以及非abstract
    • 如果任何代理接口是非public的,代理类就是非public的
    • 代理类的非限定名是未指定的。类名中"$Proxy"部分应该是,然而,这为代理类保留了。
    • 一个代理类继承自java.lang.reflect.Proxy
    • 一个代理类准确的按顺序实现了创建时的指定的接口
    • 如果一个代理类实现了一个非public接口,那么它需要和那个接口定义在同一个包内。否则,代理类的包名是不确定的,既不是同一个类加载器定义的类也不是具有特定签名的相同包。
    • 因为一个代理类创建时实现了所有指定接口,在该类对象上调用getInterfaces会返回相同的接口列表数组,调用getMethod,会返回一个Method对象的数组,该数组包含那些接口的所有方法。
    • 如果一个类是通过Proxy.getProxyClass,或该类通过Proxy.newProxyInstance的结果对象得到的,那么Proxy.isProxyClass方法会返回真。
    • 未翻译
    • 每一个代理类都有一个接收一个参数的构造器,接收的参数为接口InvocationHandler的实现,来为代理对象设置一个调用处理器。除了通过反射拿到公共的构造器,一个代理实例也可以通过Proxy.newProxyInstance方法来创建,该方法组合了Proxy.getProxyClass以及使用调用处理器构造该对象的步骤。

    示例代码:

    package reflection;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    import static java.lang.System.out;
    
    /**
     * Created by jintaox on 2017/3/14.
     */
    public class UseProxy {
    
    
        public static void main(String[] args) {
            Class clazzFoo = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[]{Foo.class});
            try {
                Constructor clazzFooConstructor = clazzFoo.getConstructor(new Class[]{InvocationHandler.class});
                Foo fooProxy = (Foo) clazzFooConstructor.newInstance(new Object[]{new MyInvocationHandler(new FooI())});
                fooProxy.work("hello world");
                out.format("isProxyClass?	%s
    ", Proxy.isProxyClass(clazzFoo));
                out.format("getInvocationHandler:	%s
    ", Proxy.getInvocationHandler(fooProxy));
                out.format("newProxyInstance...
    ");
                Foo fooProxy1 = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[]{Foo.class}, new MyInvocationHandler(new FooI()));
                fooProxy1.work("this way");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    class MyInvocationHandler implements InvocationHandler {
        private Object targetObj;
    
        public MyInvocationHandler(Object targetObj) {
            this.targetObj = targetObj;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("what proxy is?"+proxy.getClass().getSimpleName());
            System.out.println("before invoke...");
            Object result = method.invoke(targetObj, args);
            System.out.println("after invode...");
            return result;
        }
    
        @Override
        public String toString() {
            return "MyInvocationHandler{" +
                    "targetObj=" + targetObj +
                    '}';
        }
    }
    
    
    interface Foo {
        String work(String msg);
    }
    
    class FooI implements Foo {
    
        @Override
        public String work(String msg) {
            System.out.println("working..." + msg);
            return "haha" + msg;
        }
    }
    
    
  • 相关阅读:
    使用微创联合M5S空气检测仪、树莓派3b+、prometheus、grafana实现空气质量持续监控告警WEB可视化
    nodejs:使用puppeteer在服务器中构建一个获取电影电视剧剧集的接口
    nodejs 使用puppeteer模块在nodejs中模拟浏览器运行,载入脚本,输出结果
    nodejs 使用http和fs模块读取网络图片,并写入到本地
    不同环境的性能测试计划
    React 应用的 Nginx 缓存控制
    被【BiliBili@稚晖君】大佬的圈粉-收集下大佬的软硬件工具
    第二章-在线编程题2-求解幸运数问题
    数据库系统概论 第一章绪论知识点 脑图笔记
    第36篇-return字节码指令
  • 原文地址:https://www.cnblogs.com/xiaojintao/p/6549841.html
Copyright © 2020-2023  润新知