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
分享到:
相关推荐
FoxyProxy 是一款高级代理服务器管理工具,是 Firefox 火狐浏览器的代理插件,相比比 SwitchProxy、ProxyButton、QuickProxy、xyzproxy、ProxyTex 等扩展提供更多的功能。 FoxyProxy 通过使用通配符、正则表达式和...
Google Chrome插件: Proxy SwitchOmega 2.5.15. 轻松快捷地管理和切换多个代理设置. 离线插件使用方法: 1. 打开Chrome -> 自定义及控制按钮(右上角) -> 更多工具 -> 扩展程序 (有可能需要打开开发者模式) 2. 拖拽...
proxy源代码,linux下的ftp 代理的源代码,大家多多支持啊
所以在这里用到了nginx的proxy_redirect指定修改被代理服务器返回的响应头中的location头域跟refresh头域数值 以下是截取nginx的一小段配置文档 server { listen 80; server_name www.boke.com; l
apache Proxy Error apache Proxy Error apache Proxy Error apache Proxy Error
ABAP 调用ABAP PROXY
1、FoxyProxy是一个高级的代理管理工具,它完全替代了Firefox有限的代理功能。它提供比SwitchProxy、ProxyButton、 QuickProxy、xyzproxy、ProxyTex、TorButton等等更多的功能。 2、装完Firefox的Foxyproxy插件后,...
2014最新版proxy lab参考答案,小伙伴快来吧!
简易高效的代理池,提供如下功能: 1. 定时抓取免费代理网站,简易可扩展 2. 使用 Redis 对代理进行存储...Github 链接:https://github.com/Python3WebSpider/ProxyPool 详情阅读:README.md,使用方法及相关信息讲解
MySQL Proxy 实现负载均衡测试 MySQL Proxy 实现负载均衡测试
它是很棒的Proxy(代理服务)验证、切换工具,如需下载Proxy List需要购买订阅服务,或者从另一个工具Proxy Switcher PRO导出代理列表。这个注册版仅供学习、研究使用,如需商用或者个人有充足预算,请到官网购买...
Elite Proxy Switcher Pro v1.24 是目前从国外论坛找到的零售注册版,官网的新版本只是免费版(只有会员购买后才可以下载专业版),免费版无法激活。它是很棒的Proxy(代理服务)验证、切换工具,如需下载Proxy List...
Tftp ProxyServer 代理服务器 源码 *=========================================================================== * * Project: tftp_proxy, a proxy for TFTP transfers through firewalls * File: tftp_...
使用mysql5.7+sharding-proxy实现分表,策略为每半年时间分一次表
esri.config.defaults.io.proxyUrl is not set所缺文件 proxy.jsp、proxy.ashx、proxy.php、proxy.config
aws-kube-proxy1.16.8版本示例文件
赠送jar包:netty-handler-proxy-4.1.68.Final.jar; 赠送原API文档:netty-handler-proxy-4.1.68.Final-javadoc.jar; 赠送源代码:netty-handler-proxy-4.1.68.Final-sources.jar; 赠送Maven依赖信息文件:netty-...
ICS lab10 WebProxy 包含 proxy.c
proxy代理程序实例和讲解 网络编程详细代码实现和讲解