1. 从一个简单例子开始,如下定义一个接口和一个接口实现:
public interface Moveable {
public void move();
}
public class Person implements Moveable {
public void move() {
System.out.println("Person remove");
}
}
现在要做的在人移动之前记录时间和输出日志,并且记录时间和输出日志的顺序可以任意控制,这中情况可以用静态代理来简单模拟,如下:
如上图,记录日志和时间可以通过两个Person的代理俩完成,两个代码如下:
public class PersonLogProxy implements Moveable {
private Moveable entity;
public PersonLogProxy(Moveable entity) {
this.entity = entity;
}
public void move() {
System.out.println("[" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S'Z'").format(new Date()) + " Person move start]");
entity.move();
System.out.println("[" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S'Z'").format(new Date()) + " Person move End]");
}
}
public class PersonTimeProxy implements Moveable {
private Moveable entity;
public PersonTimeProxy(Moveable entity) {
this.entity = entity;
}
public void move() {
Date start = new Date();
System.out.println("START...");
entity.move();
System.out.println("END, TOTAL APENT: " + (new Date().getTime() - start.getTime()) + " MILLISECONDS.");
}
}
如我们提出的问题,我们要实现先记录日志,再记录时间,可以执行下面代码:
Moveable person = new Person();
Moveable timeProxy = new PersonTimeProxy(person);
Moveable logProxy = new PersonLogProxy(timeProxy);
logProxy.move();
运行结果:
[2010-08-30T17:15:09.437Z Person move start]
START...
Person remove
END, TOTAL APENT: 3984 MILLISECONDS.
[2010-08-30T17:15:13.437Z Person move End]
此种情况可以用下面时序图描述
PersonLogProxy调运PersonTimeProxy,然后PersonTimeProxcy调运Person执行move方法,然后依次返回结束;
如我们要实现先记录时间,再记录日志,可以执行下面代码:
Moveable person = new Person();
Moveable logProxy = new PersonLogProxy(person);
Moveable timeProxy = new PersonTimeProxy(logProxy);
timeProxy.move();
运行结果;
START...
[2010-08-30T17:23:27.281Z Person move start]
Person remove
[2010-08-30T17:23:29.453Z Person move End]
END, TOTAL APENT: 2203 MILLISECONDS.
同样先记录时间,在记录日志可以用下图说明
PersonTimeProxy调运PersonLogProxy,然后PersonTimeProxcy调运Person执行move方法,然后依次返回结束;
上面过程为简单静态代理,PersonTimeProxy和PersonLogProxy为Person代理,通过这种方式可以灵活实现先记录日志,或先记录时间的逻辑控制。
2. 动态代理开始
动态代理从字面上理解就是所需的代理类如上面PersonTimeProxy等不需要我们手动去完成,而是由程序动态的生成;java.lang.reflect.Proxy是JDK中用来产生动态代理的类,我们先简单模仿java.lang.reflect.Proxy生成动态代理类的过程,以动态生成运行PersonTimeProxy为例来说明,如下图所示:
如上图所示要完成动态生成Person的时间代理大致需要3个步骤:
第一:生成PersonTimeProxy.java临时文件,此文件是一个Java文件,实际JDK包中它没有删除文件,而是直接生成二进制文件;
第二:编译第一步生成的文件,.java文件需要编译成.class文件才可以运行,所以这一步主要是如何将PersonTimeProxy.java编译成PersonTimeProxy.class文件;
第三:运行第二步产生的PersonTimeProxy.class文件,首先需要将其加载到内存中,常用加载.class文件的方式是java.lang.ClassLoader及其子类,这里用URLClassLoader(),因为URLClassLoader不需要从他父类获得(其他的类加载器都需要从他的父类获得):
按照上面三步给出我写的代码:
package com.learn.proxy.test;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import com.learn.proxy.dynamic.Moveable;
import com.learn.proxy.dynamic.Person;
public class DynamicProxySimulation {
public static void main(String[] args) throws IOException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
//Step 1
String str =
" package com.learn.proxy.dynamic; " + "\r\n" +
" " + "\r\n" +
" import java.util.Date; " + "\r\n" +
" " + "\r\n" +
" public class PersonTimeProxy implements Moveable { " + "\r\n" +
" private Moveable entity; " + "\r\n" +
" public PersonTimeProxy(Moveable entity) { " + "\r\n" +
" this.entity = entity; " + "\r\n" +
" } " + "\r\n" +
" public void move() { " + "\r\n" +
" Date start = new Date(); " + "\r\n" +
" System.out.println(\"START...\"); " + "\r\n" +
" entity.move(); " + "\r\n" +
" System.out.println(\"END, TOTAL APENT: \" + (new Date().getTime() - start.getTime()) + \" MILLISECONDS.\");" + "\r\n" +
" } " + "\r\n" +
" " + "\r\n" +
" } " + "\r\n" ;
String fileName = System.getProperty("user.dir") + "/proxy/com/learn/proxy/dynamic/PersonTimeProxy.java";
File file = new File(fileName);
FileWriter writer = new FileWriter(file);
writer.write(str);
writer.flush();
writer.close();
//Step 2
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable units = fileManager.getJavaFileObjects(fileName);
CompilationTask task = compiler.getTask(null, fileManager, null, null, null, units);
task.call();
fileManager.close();
file.delete();
//Step 3
fileName = fileName.substring(0, fileName.length()- 4) + "class";
URL[] urls = new URL[]{new URL("file://" + System.getProperty("user.dir") + "/proxy/")};
URLClassLoader urlClassLoader = new URLClassLoader(urls);
Class c = urlClassLoader.loadClass("com.learn.proxy.dynamic.PersonTimeProxy");
//Step 4
Constructor ctr = c.getDeclaredConstructor(Moveable.class);
Moveable m = (Moveable) ctr.newInstance(new Person());
m.move();
}
}
上面代码中多出的第四步是验证代码,运行后结果如下:
START...
Person remove
END, TOTAL APENT: 8110 MILLISECONDS.
结果显示记录了人移动的时间。
分析:在动态代理开始种虽然我们没有类PersonTimeProxy,但我们却通过DynamicProxySimulation类完成了静态的 PersonTimeProxy类的功能如上就是简单的动态代理原理;
PS……接下来先继续模拟java.lang.reflect.Proxy,然后总的分析JDK中的java.lang.reflect.Proxy类
- 大小: 8.4 KB
- 大小: 5.5 KB
- 大小: 5.8 KB
- 大小: 19.3 KB
分享到:
相关推荐
配置时同样需要将`proxy.ashx`部署到服务器,并在ArcGIS JavaScript API中设置`proxyUrl`属性。 **proxy.php** 是PHP语言实现的代理服务,适用于PHP环境,如Apache或Nginx。对于那些基于PHP的Web应用,可以使用`...
Proxy和Stub的作用是解决进程间通信的问题,使得不同地址空间的应用程序可以透明地调用彼此的功能。 3. **MergeModule (x86)**:MergeModule是一个MSI(Microsoft Installer)模块,用于将组件打包到安装程序中。...
在SAP系统中,ABAP调用ABAP Proxy是一种常见的技术操作,用于在不同系统间或者同一系统内的组件之间实现通信。ABAP Proxy是SAP提供的一个强大的接口技术,它允许开发者创建安全、高效的远程调用机制。接下来,我们将...
《GoProxy-Android:全能代理服务器在安卓平台的应用与实现》 GoProxy-Android是由snail007/goproxy团队开发的一款适用于安卓系统的全能代理服务器应用。此项目旨在为移动设备提供强大的网络代理功能,使得用户能够...
在讨论Nginx的proxy_redirect指令时,我们首先要明确其在Nginx配置中的作用和重要性。proxy_redirect指令主要用于在反向代理过程中修改响应头中的Location和Refresh字段值。在Web服务器配置中,特别是在使用Nginx...
接下来我们将深入探讨标题和描述中涉及的“sharding-proxy实现分表”这一主题。 ### 1. 分库分表介绍 分库分表是数据库水平扩展的一种常见策略,用于解决单表数据量过大导致的性能问题。随着业务的增长,数据量...
FoxyProxy 是一款高级代理服务器管理工具,是 Firefox 火狐浏览器的代理插件,相比比 SwitchProxy、ProxyButton、QuickProxy、xyzproxy、ProxyTex 等扩展提供更多的功能。 FoxyProxy 通过使用通配符、正则表达式和...
《InfluxDB与Influx-Proxy的深度解析》 InfluxDB是一款专为时间序列数据设计的开源数据库,尤其在监控、物联网(IoT)、性能指标和其他大数据领域有着广泛的应用。而"Influx-proxy"则可能是一个针对InfluxDB的代理...
Google Chrome插件: Proxy SwitchOmega 2.5.15. 轻松快捷地管理和切换多个代理设置. 离线插件使用方法: 1. 打开Chrome -> 自定义及控制按钮(右上角) -> 更多工具 -> 扩展程序 (有可能需要打开开发者模式) 2. 拖拽...
"ArcGIS JS API跨域配置 Proxy 代理" ArcGIS JS API 跨域配置是指在 JS 开发中遇到的访问本地服务和外网服务的问题,需要使用 Proxy 代理来解决跨域访问文件的问题。ArcGIS 的帮助中已经有了相关的介绍和使用配置。...
Proxy和Mycat是两种常用的中间件,用于实现这些功能。本篇文章将深入探讨proxy和Mycat的对比测试,以及如何在MySQL主从架构中进行测试。 首先,我们来看proxy。Proxy通常指的是数据库代理服务器,它位于应用服务器...
`dma-proxy.c`、`dma-proxy-test.c`、`dma-proxy.h` 这些文件名暗示了它们在实现或测试dma-proxy的功能中起到的作用: 1. `dma-proxy.c`: 这通常是一个C语言源代码文件,其中包含了dma-proxy的主要实现逻辑。它可能...
在本文中,我们将深入探讨“proxy代理程序”的概念以及如何实现一个简单的代理服务。网络编程是计算机科学中的一个重要领域,而代理程序在此中扮演着关键角色,它允许客户端通过中间服务器来访问其他网络资源,从而...
MySQL Proxy 是一个开源工具,由 MySQL AB 公司开发,允许用户在 MySQL 客户端和服务器之间插入一个代理层。这个代理层可以用来监控、分析或者修改通信数据,为数据库管理提供了一种灵活的解决方案。`mysql-proxy-...
proxy源代码,linux下的ftp 代理的源代码,大家多多支持啊
Java ProxyServer是一个基于Java实现的代理服务器类,它在客户端和服务器之间起到了中继的作用,允许数据在两者间传输。代理服务器在计算机网络中的主要功能是提供代理服务,它可以隐藏客户端的真实身份,增加网络...
Charles Proxy主要用于Web开发中,以便于开发者调试和测试其网站或应用程序的网络服务。 版本4.6.5是Charles Proxy的一个特定版本,作为一款成熟的工具,它具有以下几个主要功能: 网络请求和响应查看:Charles...
proxy2proxy 多级协议代理软件当前支持32/64位Windows7/8/10等操作系统。 proxy2proxy 多级协议代理软件特点: 1)支持单级/多级协议代理服务。 2)支持 HTTP/HTTPS 协议网络代理。 3)支持大规模网络...