`

(五) 代理

 
阅读更多

代理(proxy),是Java SE 1.3新增加的特性。利用代理可以在运行时创建一个实现了一组给定接口的新类。
这种功能只有编译时无法确定需要实现哪个接口时才有必要使用。

使用场景:
有一个表示接口的Class对象(有可能只包含一个接口),它的确切类型在编译时无法知道。要想构造一个实现这些接口的类,就需要使用newInstance方法或反射找出这个类的构造器。但是,不能实例化一个接口,需要在程序运行状态时定义一个新类。

解决办法:
(1)有些程序会生成代码,将这些代码放置在一个文件中;调用编译器,然后再加载结果类文件。这样做速度会比较慢,并且需要将编译器与程序放在一起。
(2)通过代理机制,代理类可以在运行时创建全新的类,这样的代理类能够实现指定的接口。

代理类具有下列方法:
(1)指定接口所需的全部方法。
(2)Object类中的全部方法,例如toString、equals等。

不能在运行时定义这些方法的新代码。而是要提供一个调用处理器(invocation handler)。
调用处理器是实现了InvocationHandler接口的类对象。在这个接口中只有一个方法:Object invoke(Object proxy, Method method, Object[] args)
无论何时调用代理方法,调用处理器的invoke方法都会被调用,并向其传递Method对象和原始的调用参数。调用处理器必须给出处理调用的方式。

要想创建一个代理对象,需要使用Proxy类的newProxyInstance方法。这方法有三个参数:
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
一个类加载器(class loader)。作为Java安全模型的一部分,对于系统类或其他类,可以使用不同的类加载器(e.g. Foo.class.getClassLoader())。用 null 表示使用默认的类加载器。
一个Class对象数组,每个元素都是需要实现的接口。
一个调用处理器。

如何定义一个处理器,能够用结果代理对象做些什么?
答案取决于打算使用代理机制解决什么问题。使用代理可能出于什么原因,例如:
(1)路由对远程服务器的方法调用。
(2)在程序运行期间,将用户接口事件与动作关联起来。
(3)为调试,跟踪方法调用。


DEMO
使用代理和调用处理器跟踪方法调用,并且定义了一个TraceHander包装器类存储包装的对象。其中invoke方法打印被调用方法的名字和参数,随后用包装好的对象作为隐式参数调用这个方法。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Random;

public class ProxyTest {
    public static void main(String[] args) {
        Object[] elements = new Object[1000];
       
        for(int i=0;i<elements.length;i++){
            Integer value = i + 1;
            InvocationHandler handler = new TraceHandler(value);
            Object proxy = Proxy.newProxyInstance(null, new Class[]{Comparable.class}, handler);
            elements[i] = proxy;
        }

        Integer key = new Random().nextInt(elements.length) + 1;
        int result = Arrays.binarySearch(elements, key);
       
        if(result >= 0){
            System.out.println(elements[result]);
        }
    }
}
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class TraceHandler implements InvocationHandler {
    private Object target;
    public TraceHandler(Object t){
        target = t;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.print(target);
        System.out.print("." + method.getName() + "(");
        if(args != null){
            for(int i=0;i<args.length;i++){
                System.out.print(args[i]);
                if(i<args.length-1){
                    System.out.print(".");
                }
            }
        }
        System.out.println(")");
        return method.invoke(target, args);
    }
}
 




在上面的DEMO中,无论何时调用proxy调用某个方法,这个方法的名字和参数就会打印出来,之后再用value调用它。
这里使用代理对象对二分查找进行跟踪。首先将用1~1000整数的代理填充数组,然后调用Arrays类中的binarySearch方法在数组中查找一个随机整数。最后,打印出与之匹配的元素。
这里,Integer类实现了Comparable接口,然而,它的compareTo方法调用了代理对象处理器的invoke方法。
注:Java SE 5.0中,Integer类实际上实现了Comparable<Integer>。然而,在运行时,所有的泛型类都被取消,代理将它们构造为原Comparable类的类对象。

binarySearch方法按下面这种方式调用:if(elements[i].compareTo(key) < 0)
由于数组中填充了代理对象,所以compareTo调用了TraceHander类中的invoke方法。这个方法打印出了方法名和参数,之后用包装好的Integer对象调用compareTo。

最后,在结尾调用: System.out.println(elements[result]);
println方法调用代理对象的toString,这个调用也会被重定向到调用处理器上。


代理类的特性
1.代理类是在程序运行过程中创建的,然而,一旦被创建,就变成了常规类,与虚拟机中的任何其他类没有什么区别。
2.所有的代理类都扩展与Proxy类,一个代理类只有一个属性,即调用处理器。它定义在Proxy的超类中,为了履行代理对象的职责,所需要的任何附加数据都必须存储在调用处理器中。如DEMO中,代理Comparable对象时,TraceHandler包装了实际的对象。
3.所有的代理类都覆盖了Object类中的方法toString、equals和hashCode。如同所有的代理方法一样,这些方法仅仅调用了调用处理器的invoke。Object类中的其他方法(如clone和getClass)没有被重新定义。
4.没有定义代理类的名字,Sun虚拟机中的Proxy类将生成一个以字符串$Proxy开头的类名。
5.对于特定的类加载器和预设的一组接口来说,只能有一个代理类。也就是说,如果使用同一个类加载器和接口数组调用两次newProxyInstance方法的话,只能够得到同一个类的两个对象,也可以利用getProxyClass方法获得这个类。
    Class proxyClass = Proxy.getProxyClass(null, interfaces);
6.代理类一定是public和final。如果代理类实现的所有接口都是public,代理类就不属于某个特定的包;否则所有非公有的接口都必须属于同一个包,同时,代理类也属于这个包。
7.可以通过调用Proxy类中的isProxyClass方法检测一个特定的Class对象是否代表一个代理类。


涉及API
 
接口 java.lang.reflect.InvocationHandler
Object invoke(Object proxy, Method method, Object[] args) : 在代理实例上处理方法调用并返回结果。

类 java.lang.reflect.Proxy
static InvocationHandler getInvocationHandler(Object proxy) : 返回指定代理实例的调用处理程序。
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) : 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。  
static boolean isProxyClass(Class<?> cl) : 当且仅当指定的类通过 getProxyClass 方法或 newProxyInstance 方法动态生成为代理类时,返回 true。也就是说c是一个代理类时返回true。
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) : 返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。

分享到:
评论

相关推荐

    代理商授权书范本五篇.pdf

    代理商授权书范本五篇.pdf 代理商授权书是一种商业文件,用于规定代理商和甲方之间的合作关系、责任和权利。下面是从给定的文件中提取的相关知识点: 一、代理商授权书的定义和作用 代理商授权书是指甲方授权乙方...

    C#实现HTTP代理

    五、使用WebProxy类 WebProxy类提供了更高级的功能,如BypassList(用于定义应绕过的地址列表)和BypassProxyOnLocal(用于决定是否对本地地址使用代理)。你可以根据需求调整这些设置。 六、注意点 1. 代理服务器...

    vos 添加代理商

    #### 五、注意事项 - **准确填写信息**:在创建账户或分配登录凭证时,请确保所有信息准确无误,尤其是代理商之间的上下级关系。 - **权限管理**:根据实际情况调整不同级别代理商的权限设置,以确保系统的安全性和...

    JDK动态代理_JDK动态代理

    #### 五、总结 通过上述示例,我们可以看到JDK动态代理如何为一个接口创建代理对象,并且能够在方法调用前后添加日志记录等功能。这种方式极大地提高了代码的可扩展性和灵活性,使得在不改变原有对象实现的情况下,...

    Spring事务五种不同的代理配置

    在类上直接使用 @Transactional 注解,Spring 会创建基于类的代理,但是这种方式可能导致一些问题,例如:无法通过子类覆盖父类的方法来改变事务属性。 第五种方式:编程式事务管理 除了声明式事务管理,Spring 还...

    华三nd 代理功能

    #### 五、配置接口为用户侧接口 - 当接口的角色为用户侧接口时,这意味着接口的邻居都是终端主机。对于此类接口上学习到的ND表项,驱动软件可以不为其分配下一跳资源,从而节省硬件资源。 - 配置命令示例: - 进入...

    免费的10个代理

    ### 五、部分免费代理地址分析 从给定的部分免费代理地址来看,这些代理主要分布在山东、天津、湖北等地,涵盖了电信、联通和移动等多个运营商的IP地址。例如: - **119.145.165.250:9000**:这是一个位于山东省的...

    一分钟了解四层七层反向代理

    ### 一分钟了解四层七层反向代理 #### 一、基本概念介绍 在深入了解四层与七层反向代理之前,我们先回顾一下代理的基本概念。代理是一种网络服务技术,它作为客户端与真实服务器之间的中介,帮助双方进行通信。 *...

    Java 动态代理详解(代理模式+静态代理+JDK动态代理+CGLIB动态代理)

    五、 对比分析 | 代理方式 | 优点 | 缺点 | | --- | --- | --- | | 静态代理 | 可以在不改变目标对象的情况下,对目标对象进行功能增强 | 需要编写代理类代码,需要维护多个代理类 | | JDK 动态代理 | 可以在运行时...

    Apache Thrift 初学小讲(五)【代理】

    在"Apache Thrift 初学小讲(五)【代理】"这篇博文中,我们将探讨Thrift如何实现代理服务,这在分布式系统中非常关键,因为代理可以提供负载均衡、安全控制、监控等功能。 1. **接口定义语言(IDL)**:Thrift ...

    关于jdk动态代理的源码剖析

    #### 五、动态代理的核心——`InvocationHandler` `InvocationHandler`是动态代理的核心接口,其主要作用是处理代理对象的方法调用。当通过代理对象调用一个方法时,该方法的调用会被委托给`InvocationHandler`实例...

    招标代理绩效考核方案.doc

    五、考察标准 本方案的考察标准包括: 1. 招标代理业务知识:考察人员对招标代理业务知识的掌握程度。 2. 职业技能:考察人员对招标代理业务操作的熟练程度。 3. 职业品行:考察人员对职业道德和职业规范的遵守...

    LR11使用代理录制--如无法使用IE浏览器录制,设置代理后可以使用谷歌,火狐录制

    #### 五、注意事项 - **安全性考虑**:使用代理服务器时,需要确保所使用的服务器安全可靠,防止敏感信息泄露。 - **性能影响**:代理服务器会增加网络延迟,可能对录制速度和精度造成一定影响。 - **浏览器兼容性*...

    IE代理超级版

    **五、网络监控** 该软件还具备网络监控功能,可以记录用户的所有网络活动,这对于企业IT管理员监控网络流量、排查问题或是家庭父母监控孩子的网络行为非常有帮助。 **六、其他特性** 除了上述功能,IE代理超级版...

    第五章代理商.docx

    《第五章代理商》主要探讨的是在市场研究项目中,XX雅兴市场研究公司与代理商之间的合作责任和流程。以下是对章节内容的详细解析: 一、项目设计阶段 在这个阶段,XX雅兴市场研究公司的主要任务是与客户沟通项目...

    路由NAT和代理的区别

    #### 五、NAT与Proxy的主要区别 - **工作层次**:NAT主要工作在网络层(ISO七层模型中的第三层),需要对IP数据包进行拆包和重组;而代理服务器通常工作在应用层(第七层),因此被称为应用网关。 - **性能差异**:...

    一篇讲动态代理的好文 <动态代理的前世今生>

    #### 五、动态代理的应用场景 1. **事务管理**:在数据访问层中,可以通过动态代理自动添加事务控制逻辑,简化业务代码。 2. **日志记录**:为方法调用增加日志记录功能,方便后期追踪调试。 3. **性能监控**:自动...

    ArcGIS JS API跨域配置 Proxy 代理

    五、Proxy 代理的作用 Proxy 代理的作用是解决跨域访问文件的问题,使得不同的 WEB 平台可以访问本地服务和外网服务。Proxy 代理可以帮助开发者更方便地访问不同的服务,从而提高开发效率。 六、总结 ArcGIS JS ...

    最新经销代理合同模板销售代理协议样式五WORD文档版本.docx

    五、结算与运输 1. 款到发货,收到货款后次日安排发货。 2. 包装费用由甲方承担,运输费用由乙方承担。 3. 独家代理时,甲方需将该区域客户引荐给乙方,乙方享有独家经营权。 4. 乙方需在地区内进行品牌宣传,提供...

    销售代理协议样式五精选.doc

    以下是对《销售代理协议样式五精选》主要内容的详细解读: 1. **代理资格确认**:甲方在选择乙方作为销售代理时,会考虑乙方的运营条件,包括独立的运营场地、完善的销售网络、充足的资金和良好的资信。此外,乙方...

Global site tag (gtag.js) - Google Analytics