Java-马士兵设计模式学习笔记-代理模式-动态代理 修改成可以任意修改代理逻辑
一、概述
1.目标:动态代理的代理逻辑可以任意修改
2.思路:
(1)要把代理逻辑抽离,站在jvm的角度思考,应独立出InvocationHandler接口,并接收被代理的对象及方法作为参数invoke(Object o, Method m),并本身作为参数传给newProxyInstance(Class interfze,InvocationHandler handler)
(2)InvocationHandler本身聚合被代理类target,以便在target的方法前后增加代理逻辑
3.知识点:
(1)按名字找方法java.lang.reflect.Method md = proxy.Movable.class.getMethod("stop");
(2)按"."拆分字符串:String [] parts = m.toString().replace("abstract ", "").split("\\.");
二、代码
1.InvocationHandler.java
2.TimeHandler.java
3.Movable.java
4.Tank.java
5.Proxy.java
6.Client.java
1.InvocationHandler.java
package proxy;
import java.lang.reflect.Method;
public interface InvocationHandler {
public void invoke(Object o, Method m);
}
2.TimeHandler.java
package proxy; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; public class TimeHandler implements InvocationHandler { //保留被代理的对象
private Object target; public TimeHandler(Object target) {
this.target = target;
} @Override
public void invoke(Object o, Method m) {
System.out.println("Time Proxy start...........");
long start = System.currentTimeMillis();
try {
//除了静态方法,方法的调用都要先已知对象,所以要把对象o作为参数传进去
m.invoke(target);
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("花费时间:"+(end - start));
System.out.println("Time Proxy end..........."); } }
3.Movable.java
package proxy;
public interface Movable {
public void move();
public void stop();
}
4.Tank.java
package proxy;
import java.util.Random;
public class Tank implements Movable {
@Override
public void move() {
System.out.println("Tank moving.......");
try {
Thread.sleep(new Random().nextInt(2000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void stop() {
System.out.println("Tank stopping.......");
}
}
5.Proxy.java
package proxy; import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
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; public class Proxy { public static Object newProxyInstance(Class interfze,InvocationHandler handler) throws Exception { String rt = "\n\r"; //拼接"实现接口方法"的字符串
String methodStr = "";
for(Method m: interfze.getMethods() ){ //取出方法的修饰符和返回值类型
String [] parts = m.toString().replace("abstract ", "").split("\\.");
String [] parts2 = parts[0].split(" "); methodStr +=
"@Override" + rt +
parts2[0]+" "+parts2[1]+" "+m.getName()+"() {" + rt +
"try{"+ rt +
"java.lang.reflect.Method md = " + interfze.getName() + ".class.getMethod(\""+m.getName()+"\");" + rt +
//传this进去其实没什么用,invoke实际是调用target的方法m.invoke(target)
"handler.invoke(this, md);" + rt +
"}catch(Exception e){"+ rt +
" e.printStackTrace();" + rt +
"}" + rt + "}"+ rt ;
} //动态代理文件的源码
String str =
"package proxy;" + rt + "public class TankTimeProxy implements " + interfze.getName() + " {"+rt+ //聚合Handler
"private InvocationHandler handler;" + rt + "public TankTimeProxy(InvocationHandler handler) {" + rt +
"this.handler = handler;" + rt +
"}" + rt + methodStr + rt + "}" ; //把源码写到java文件里
File file = new File(System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.java");
FileWriter fw = new FileWriter(file);
fw.write(str);
fw.flush();
fw.close(); //编译源码,生成class,注意编译环境要换成jdk才有compiler,单纯的jre没有compiler,会空指针错误
JavaCompiler jc = ToolProvider.getSystemJavaCompiler(); //文件管事器
StandardJavaFileManager fileMgr = jc.getStandardFileManager(null, null, null); //编译单元
Iterable units = fileMgr.getJavaFileObjects(file); //编译任务
CompilationTask t = jc.getTask(null, fileMgr, null, null, null, units); //编译
t.call();
fileMgr.close(); //把类load到内存里
URL[] urls = new URL[] {new URL("file:/"+System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.class")};
URLClassLoader uc = new URLClassLoader(urls);
Class c = uc.loadClass("proxy.TankTimeProxy"); //生成实例
//return c.newInstance(); //c.newInstance()会调用无参数的Construtor,若类没有无参的Constructor时会出错
//Constructor ctr = c.getConstructor(interfze);
Constructor ctr = c.getConstructor(InvocationHandler.class);
return ctr.newInstance(handler);
}
}
6.Client.java
package proxy;
import java.io.IOException;
import org.junit.Test;
public class Client {
@Test
public void testProxy() throws Exception{
Movable m = (Movable)Proxy.newProxyInstance(Movable.class, new TimeHandler(new Tank()));
m.move();
m.stop();
}
}
三、运行结果

Java-马士兵设计模式学习笔记-代理模式-动态代理 修改成可以任意修改代理逻辑的更多相关文章
- Java-马士兵设计模式学习笔记-命令模式
一.概述 命令模式 二.代码 1.Client.java public class Client { public void request(Server server){ server.addCom ...
- Java-马士兵设计模式学习笔记-桥接模式
一.概述 1.桥接模式的应用情况:(1)两个维度扩展(2)排列组合 二.代码 1.Gift.java public class Gift { protected GiftImpl giftImpl; ...
- Java-马士兵设计模式学习笔记-工厂模式-抽象工厂模式
一.概述 1.抽象工厂:当情况是需要产生一系列产品,若需更换产品,则要求一系列产品一起换,且要控制一系列产品的产生过程,此时可考虑抽象工厂模式.例:小明装修屋子,把电视.冰箱都替换掉,他这次需要把电视 ...
- Java-马士兵设计模式学习笔记-工厂模式-简单工厂
一.概述 1.目标:要控制任意类型交通工具的生产模式 2.目标有两层意思(1)任意类型 (2)生产模式,所以对应的,要这两个层面上抽象(Movable,VehicleFactory),利用接口,实现多 ...
- Java-马士兵设计模式学习笔记-策略模式-模拟 Comparator接口
续上一篇 <Java 模拟 Comparable接口> 一.Teacher类及Student类的比较大小方式是不固定的,比如老师除了比较职称外,还可比较工龄大小,年龄大小等.则定义Com ...
- Java-马士兵设计模式学习笔记-迭代器模式-模仿Collectin ArrayList LinckedList
Java Iterator模式 Java Iterator模式, 模仿Collectin ArrayList LinckedList 一.有如下几个类 1.接口Collection.java 2.接口 ...
- Java-马士兵设计模式学习笔记-建造者模式
一.概述 二.代码 1.Animal.java public interface Animal { public void bark(); } 2.Dog.java public class Dog ...
- Java-马士兵设计模式学习笔记-工厂模式-用Jdom模拟Spring
一.概述 1.目标:模拟Spring的Ioc 2.用到的知识点:利用jdom的xpath读取xml文件,反射 二.有如下文件: 1.applicationContext.xml <?xml ve ...
- Java-马士兵设计模式学习笔记-工厂模式-模拟Spring读取Properties文件
一.目标:读取properties文件,获得类名来生成对象 二.类 1.Movable.java public interface Movable { void run(); } 2.Car.java ...
- Java-马士兵设计模式学习笔记-工厂模式-单例及多例
一.单例的作用是用于控制类的生成方式,而不让外部类任意new对象 1.Car.java import java.util.ArrayList; import java.util.List; publi ...
随机推荐
- 网页设计师必备的10个CSS技巧
CSS是网页设计师的基础,对CSS的了解能使他们能够设计出更加美观别致的网页.使用CSS技巧来巧妙地处理CSS是非常令设计师着迷的事情.在CSS的深海世界里有很多有意思的东西,你只需要找到最适合你的就 ...
- 程序开发心理学阅读笔记——第I篇
1.软件的任务是为了解决某一特定的问题,而软件开发者的任务却需要解决一系列问题.2.温伯格说,我们不能要求每个人都聪明异常,能够解决所有难题:但是我们必须持续思考,因为只有如此,我们才能明白自己在做什 ...
- NEST.net Client For Elasticsearch简单应用
NEST.net Client For Elasticsearch简单应用 由于最近的一个项目中的搜索部分要用到 Elasticsearch 来实现搜索功能,苦于英文差及该方面的系统性资料不好找,在实 ...
- sql中having的使用
where 和having有什么区别? where 是group by之前进行筛选,having是group by 之后进行统计的筛选,一般having会和group by一起使用,结合聚合函数,统计 ...
- 《我是一只it小小鸟》
<我是一只it小小鸟>一书虽然内容不多,但里面的故事极其励志,耐人寻味.虽然只花不多的时间阅读这本书,它给我的影响将会伴随一生. 他们是来自不同的院校,或本科,或半路转行:工作在不同的场所 ...
- 【转载】MyBatis之传入参数
原文地址:http://blog.csdn.net/liaoxiaohua1981/article/details/6862764 在MyBatis的select.insert.update.dele ...
- Netty 对通讯协议结构设计的启发和总结
Netty 通讯协议结构设计的总结 key words: 通信,协议,结构设计,netty,解码器,LengthFieldBasedFrameDecoder 原创 包含与机器/设备的通讯协议结构的设计 ...
- BZOJ 1029: [JSOI2007]建筑抢修 贪心
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1029 小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落 ...
- Java内存模型(JMM)
参考: 1. http://www.tuicool.com/articles/UVzuQb
- 浅谈css中的position
什么是position,根据css 2.1中的描述,position和float的值决定了浏览器要采用那种定位算法来计算元素盒子的具体位置.先避开float不谈,本文主要介绍position属性的不同 ...