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

1 package proxy;
2
3 import java.lang.reflect.Method;
4
5 public interface InvocationHandler {
6     public void invoke(Object o, Method m);
7 }

2.TimeHandler.java

 1 package proxy;
 2
 3 import java.lang.reflect.InvocationTargetException;
 4 import java.lang.reflect.Method;
 5
 6 public class TimeHandler implements InvocationHandler {
 7
 8     //保留被代理的对象
 9     private Object target;
10
11     public TimeHandler(Object target) {
12         this.target = target;
13     }
14
15     @Override
16     public void invoke(Object o, Method m) {
17         System.out.println("Time Proxy start...........");
18         long start = System.currentTimeMillis();
19         try {
20             //除了静态方法,方法的调用都要先已知对象,所以要把对象o作为参数传进去
21             m.invoke(target);
22         } catch (Exception e) {
23             e.printStackTrace();
24         }
25         long end = System.currentTimeMillis();
26         System.out.println("花费时间:"+(end - start));
27         System.out.println("Time Proxy end...........");
28
29     }
30
31 }

3.Movable.java

1 package proxy;
2
3 public interface Movable {
4     public void move();
5     public void stop();
6 }

4.Tank.java

 1 package proxy;
 2
 3 import java.util.Random;
 4
 5 public class Tank implements Movable {
 6
 7     @Override
 8     public void move() {
 9         System.out.println("Tank moving.......");
10         try {
11             Thread.sleep(new Random().nextInt(2000));
12         } catch (InterruptedException e) {
13             e.printStackTrace();
14         }
15     }
16
17     @Override
18     public void stop() {
19         System.out.println("Tank stopping.......");
20
21     }
22
23 }

5.Proxy.java

 1 package proxy;
 2
 3 import java.io.File;
 4 import java.io.FileWriter;
 5 import java.lang.reflect.Constructor;
 6 import java.lang.reflect.Method;
 7 import java.net.URL;
 8 import java.net.URLClassLoader;
 9
10 import javax.tools.JavaCompiler;
11 import javax.tools.JavaCompiler.CompilationTask;
12 import javax.tools.StandardJavaFileManager;
13 import javax.tools.ToolProvider;
14
15 public class Proxy {
16
17     public static Object newProxyInstance(Class interfze,InvocationHandler handler) throws Exception {
18
19         String rt = "\n\r";
20
21         //拼接"实现接口方法"的字符串
22         String methodStr = "";
23         for(Method m: interfze.getMethods() ){
24
25             //取出方法的修饰符和返回值类型
26             String [] parts = m.toString().replace("abstract ", "").split("\\.");
27             String [] parts2 = parts[0].split(" ");
28
29             methodStr +=
30             "@Override" + rt +
31             parts2[0]+" "+parts2[1]+" "+m.getName()+"() {" + rt +
32             "try{"+ rt +
33                 "java.lang.reflect.Method md = " + interfze.getName() + ".class.getMethod(\""+m.getName()+"\");" + rt +
34                 //传this进去其实没什么用,invoke实际是调用target的方法m.invoke(target)
35                 "handler.invoke(this, md);" + rt +
36             "}catch(Exception e){"+ rt +
37             "    e.printStackTrace();" + rt +
38             "}" + rt +
39
40
41             "}"+ rt ;
42         }
43
44
45         //动态代理文件的源码
46         String str =
47         "package proxy;" + rt +
48
49         "public class TankTimeProxy implements " + interfze.getName() + " {"+rt+
50
51
52             //聚合Handler
53             "private InvocationHandler handler;" + rt +
54
55             "public TankTimeProxy(InvocationHandler handler) {" + rt +
56                 "this.handler = handler;" + rt +
57             "}" + rt +
58
59             methodStr + rt +
60
61         "}" ;
62
63         //把源码写到java文件里
64         File file = new File(System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.java");
65         FileWriter fw = new FileWriter(file);
66         fw.write(str);
67         fw.flush();
68         fw.close();
69
70         //编译源码,生成class,注意编译环境要换成jdk才有compiler,单纯的jre没有compiler,会空指针错误
71         JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
72
73         //文件管事器
74         StandardJavaFileManager fileMgr = jc.getStandardFileManager(null, null, null);
75
76         //编译单元
77         Iterable units = fileMgr.getJavaFileObjects(file);
78
79         //编译任务
80         CompilationTask t = jc.getTask(null, fileMgr, null, null, null, units);
81
82         //编译
83         t.call();
84         fileMgr.close();
85
86         //把类load到内存里
87         URL[] urls = new URL[] {new URL("file:/"+System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.class")};
88         URLClassLoader uc = new URLClassLoader(urls);
89         Class c = uc.loadClass("proxy.TankTimeProxy");
90
91         //生成实例
92         //return c.newInstance(); //c.newInstance()会调用无参数的Construtor,若类没有无参的Constructor时会出错
93         //Constructor ctr = c.getConstructor(interfze);
94         Constructor ctr = c.getConstructor(InvocationHandler.class);
95         return ctr.newInstance(handler);
96     }
97 }

6.Client.java

 1 package proxy;
 2
 3 import java.io.IOException;
 4
 5 import org.junit.Test;
 6
 7 public class Client {
 8
 9     @Test
10     public void testProxy() throws Exception{
11
12         Movable m = (Movable)Proxy.newProxyInstance(Movable.class, new TimeHandler(new Tank()));
13         m.move();
14         m.stop();
15
16     }
17 }

三、运行结果

时间: 2024-10-29 05:22:57

Java 动态代理 修改成可以任意修改代理逻辑的相关文章

android 用java动态设置布局(增添删除修改布局)

XML对开发者来说十分的方便,不仅使用起来简单,而且能够及时调试,修改界面之后马上能看到效果. Java设置布局不具有这个优势.但是java却可以动态对布局进行操作,这是xml所做不到的.笔者认为,新手索要掌握的java动态设置布局主要有两点,一方面是对布局的属性进行修改,另一方面是增添和删除控件. 首先说一下动态设置布局在项目中的应用,拿高德地图举个例子,如下图:    我们可以看到,高德地图的默认界面与点击地图之后的界面是不一样的,上面同样的控件在layout中的位置也不一样,这个用xml便

Mac把socks5代理转换成http/https的代理

GFW临幸,pip一蹶不振,不争气的pip还只支持http的代理. ss代理是socks的,监听于1080端口, 于是我用privoxy这个工具转换socks成http 下载:http://download.csdn.net/detail/u010211892/8413677 安装完后该 /usr/local/etc/privoxy/config文件 引用http://blog.newnaw.com/?p=616一段 修改Privoxy的配置文件,找到listen-address这一行,将其修改

java 动态代理范例 (jdk ,cglib)

JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建时期,代理类可以分为两种. 1)静态代理:由程序员创建或特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就

Java 动态代理 修改成可以代理任意接口

一.概述 1.目标:把Proxy修改成可以代理任意接口及其任意方法 2.思路: (1)代理任意接口:把接口类型作为参数传给Proxy的newProxyInstance(Class interfze) (2)代理任意方法:用interfze.getMethods()取出所有方法,拼接实现方法的字符串 二.代码 1.Movable.java 2.Tank.java 3.Proxy.java 4.Client.java 1.Movable.java 1 package proxy; 2 3 publi

java动态代理(JDK和cglib)

转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建时期,

《转》java动态代理(JDK和cglib)

该文章转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建

《转》JAVA动态代理(JDK和CGLIB)

该文章转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建

(转)java动态代理(JDK和cglib)

博文转自http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建时期

java动态代理与老式AOP实现

JAVA的动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建时期,代理类可以分为两种. class文件就已经存在了. 动态代理:在程序运行时,运用反射机制动态创建而成. 首先看一下静态代理: /** *