代理(proxy)

利用代理可以在运行时创建一个实现了一组给定接口的新类。这种功能只有在编译时无法确定需要实现哪个接口时才有必要使用。

何时使用代理

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

代理类可以在运行时创建全新的类。这样的代理类能够实现指定的接口。尤其是,它具有下列方法:

  • 指定接口所需要的全部方法
  • Object类中的全部方法,例如, toString, equals等。

创建代理对象

要想创建一个代理对象,需要使用Proxy类的newProxyInstance方法。这个方法有三个参数:

  • 一个类加载器(class loader)。
  • 一个Class对象数组,每个元素都是需要实现的接口。
  • 一个调用处理器

还有两个需要解决的问题。如何定义一个处理器?能够用结果代理对象做些什么?当然,这两个问题的答案取决于打算使用代理机制解决什么问题。比如

  • 路由对远程服务器的方法调用
  • 调试,跟踪
  • log

Demo

我们定义一个处理器,用来打印调用的参数

public class TraceHandler implements InvocationHandler {

    private Object target;

    public TraceHandler(Object target) {
this.target = target;
} @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);
}
}

接下来,我们用它来代理Comparable接口,看看怎么调用。比如Arrays的二分查找方法binarySearch

    @Test
public void traceBinarySearch() {
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]);
}
}

控制台打印结果:

500.compareTo(94)
250.compareTo(94)
125.compareTo(94)
62.compareTo(94)
93.compareTo(94)
109.compareTo(94)
101.compareTo(94)
97.compareTo(94)
95.compareTo(94)
94.compareTo(94)
94.toString()
94

代理类的特性

  • 代理类是在运行过程中创建的,创建完毕后和常规类相同,虚拟机同等对待。
  • 所有的代理类都扩展于Proxy类。一个代理类只有一个实例域---调用处理器,它定义在Proxy的超类中。
  • 没有定义代理类的名字,Sun虚拟机中的Proxy类将生成一个以字符串$Proxy开头的类名。
  • 对于特定的类加载器和预设的一组接口来说,只能有一个代理类。也就是说,如果使用同一个类加载器和接口数组调用两次newProxyInstance方法的话,只能得到同一个类的两个对象。比如class com.sun.proxy.$Proxy4.可以使用getProxyClass来获取这个类。
  • 代理类一定是public final的。
  • 可以通过Proxy.isProxyClass方法检测一个特定的Class对象是否代表一个代理类。

来源

  • Java核心技术

Java代理类Proxy的用法的更多相关文章

  1. Java代理设计模式(Proxy)的四种具体实现:静态代理和动态代理

    面试问题:Java里的代理设计模式(Proxy Design Pattern)一共有几种实现方式?这个题目很像孔乙己问"茴香豆的茴字有哪几种写法?" 所谓代理模式,是指客户端(Cl ...

  2. Java代理设计模式(Proxy)的几种具体实现

    Proxy是一种结构设计模型,主要解决对象直接访问带来的问题,代理又分为静态代理和动态代理(JDK代理.CGLIB代理. 静态代理:又程序创建的代理类,或者特定的工具类,在平时开发中经常用到这种代理模 ...

  3. 深入解析OpenCart的代理类proxy

    1.什么是代理类 代理类指的是连接远程对象或不可见对象的接口,通常被客户端调用来连接真实的服务对象.更准确的定义参见维基百科 2.代理的作用 作为一个包装类,提供额外的功能 延迟加载 在本文讲到的op ...

  4. java枚举类的常见用法

    枚举类型(Enumerated Type) 很早就出现在编程语言中,它被用来将一组类似的值包含到一种类型当中.而这种枚举类型的名称则会被定义成独一无二的类型描述符,在这一点上和常量的定义相似.不过相比 ...

  5. java代理类及AOP

    1.代理架构图 2.AOP 3.动态代理概念 4.动态代理工作原理图

  6. Java中的动态代理以及Proxy类的偷瞄

    动态代理机制 所谓动态代理,即通过代理类Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联. Java动态代理类位于Java.lang.reflect包 ...

  7. Java的动态代理(dynamic proxy)

    什么是动态代理(dynamic proxy) 动态代理(以下称代理),利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对 ...

  8. 探索Mybatis之JDK动态代理:探究Proxy.newProxyInstance()生成的代理类解析

    Mybatis的Mapper接口UserMapper 1 package com.safin.Mapper; 2 3 import com.safin.Pojo.User; 4 5 import ja ...

  9. java代理通俗简单解析

    1         代理 1.1            代理的概念和作用 代理的概念很好理解,就像黄牛代替票务公司给你提供票,经纪人代理艺人和别人谈合作.Java的代理是指实现类作为代理类的属性对象, ...

随机推荐

  1. js常用但是不容易记住的代码

    <!-- iframe 自适应高度度 --><iframe src="__CONTROLLER__/showlist" frameborder="0&q ...

  2. P站全新官方精选集Pixivision

    P站是一个主要由日本艺术家所组成的虚拟社群,主打插画.漫画.二次元作品网上沟通. 不过好消息是,P站全新的精选网站Pixivision上线了,多种语言界面,国内用户访问毫无压力. 近期精选的一系列作品 ...

  3. linux远程执行ssh禁用交互方法

    ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${user}@${ip} ${cmd}

  4. C# .NET 使用 NPOI 生成 .xlsx 格式 Excel

    IWorkbook workbook = new XSSFWorkbook(); ISheet sheet = workbook.CreateSheet("-"); IRow ro ...

  5. 不知道怎么向女神表白?Python三大神技分分钟带你成功逆袭!

    一行python的表白 首先祭出绝招,用1行python表白: print(' '.join([''.join([('I LOVE U'[(x-y) % 8] if ( (x*0.05)**2 + ( ...

  6. Latex学习笔记 第一章

    1.使用空行分段. 空行只起分段的作用,使用过多的空行并不起增大段间间距的作用. 2.段前不用打空格,LateX会自动完成文字的缩进. 即使打了也会被自动忽略. 3.通常汉字后面的空格会被忽略,其他符 ...

  7. JS基本语法---while循环---练习

    JS基本语法---while循环---练习 练习1: 求6的阶乘 var ji = 1;//存储最终的阶乘的结果 var i = 1;//开始的数字 while (i <= 6) { ji *= ...

  8. MySQL基于报错注入1

    0x1 判断注入点: http://www.xxxx.ro/s.php?id=1' 那么尝试闭合下单引号 http://www.xxxx.ro/s.php?id=1' --+ 0x2 枚举下表的列 h ...

  9. 使用 gitlab 进行代码管理

    这里使用 gitlab 做服务器, 客户端主要使用 git extensions. ============================= gitlab 项目成员类型: ============= ...

  10. Troubleshooting ORA-30036 - Unable To Extend Undo Tablespace (Doc ID 460481.1)

    Troubleshooting ORA-30036 - Unable To Extend Undo Tablespace (Doc ID 460481.1) APPLIES TO: Oracle Da ...