标签:int   user   ssl   还需要   file   ace   dir   系统   net   
Java-马士兵动态代理模式 
模拟jdk的动态代理的实现原理, 这些东西没有必要写出来,写项目的时候用不上,主要是面试和理解原理;
?
有些工具可以直接生成二进制码,没有必要生成文件。
代理模式-聚合与继承方式比较
参考地址:http://www.cnblogs.com/shamgod/p/4591782.html
	
?
一、概述
			
1.目标:要在Tank的move()方法做时间代理及日志代理(可以设想以后还要增加很多代理处理),且代理间的顺序可活更换
			
2.思路:
			
(1)聚合:代理类聚合了被代理类,且代理类及被代理类都实现了movable接口,则可实现灵活多变,具体看代码
			
(2)继承:继承不够灵活,具体看代码
			
?
?
二、代码
			
1.Movable.java
		
2.Tank.java
		
3.TankTimeProxy.java
		
4.TankLogProxy.java
		
5.Tank2Time.java
		
6.Tank3Log.java
		
7.Client.java
		
?1.Movable.java
		
public
					interface Movable {
??public
					void move();
?}
?
?
2.Tank.java
		
import java.util.Random;
?
public
					class Tank implements Movable {
?
????@Override
????public
					void move() {
????????System.out.println("Tank moving.......");
????????try {
????????????Thread.sleep(new Random().nextInt(5000));
????????} catch (InterruptedException e) {
????????????e.printStackTrace();
????????}
????}
?
}
?
?
3.TankTimeProxy.java
		
public
					class TankTimeProxy implements Movable {
?
????Movable m;
?
????public TankTimeProxy(Movable m) {
????????this.m = m;
????}
?
????@Override
????public
					void move() {
????????System.out.println("Time Proxy start...........");
????????long start = System.currentTimeMillis();
????????m.move();
????????long end = System.currentTimeMillis();
????????System.out.println("花费时间:"+(end - start));
????????System.out.println("Time Proxy end...........");
????}
?
}
?
4.TankLogProxy.java
		
public
					class TankLogProxy implements Movable {
????Movable m;
????public TankLogProxy(Movable m) {
????????this.m = m;
????}
????@Override
????public
					void move() {
????????System.out.println("Log Proxy start...........");
????????m.move();
????????System.out.println("Log Proxy end...........");
????}
}
?
?
5.Tank2Time.java
		
public
					class Tank2Time extends Tank {
?
????public
					void move(){
????????System.out.println("Tank2 time start...........");
????????long start = System.currentTimeMillis();
????????super.move();
????????long end = System.currentTimeMillis();
????????System.out.println("花费时间:"+(end - start));
????????System.out.println("Tank2 time end...........");
????}
}
?
?
6.Tank3Log.java
		
public
					class Tank3Log extends Tank2Time {
?
????public
					void move(){
????????System.out.println("Tank3Log start...........");
????????super.move();
????????System.out.println("Tank3Log end...........");
????}
}
?
?
7.Client.java
		
public
					class Client {
?
????@Test
????public
					void testProxy(){
????????Tank t = new Tank();
????????Movable m;
????????//一、聚合的方式(较灵活,因为实现了接口)
				
????????//1.1聚合方式的代理,先日志代理,后时间代理
				
????????TankTimeProxy ttp1 = new TankTimeProxy(t);
????????TankLogProxy tlp1 = new TankLogProxy(ttp1);
????????m = tlp1;
????????m.move();
????????System.out.println("\n==============================分隔线==========================\n");
????????//1.2聚合方式的代理,先时间代理,后日志代理(可以灵活切换顺序)
				
????????TankLogProxy tlp2 = new TankLogProxy(t);
????????TankTimeProxy ttp2 = new TankTimeProxy(tlp2);
????????m = ttp2;
????????m.move();
????????System.out.println("\n==============================分隔线==========================\n");
????????//二、继承的方式
				
????????//2.1代理时间
				
????????Tank2Time t2 = new Tank2Time();
????????t2.move();
????????System.out.println("\n==============================分隔线==========================\n");
????????//2.2先代理日志,后时间,不能灵活切换
				
????????Tank3Log t3 = new Tank3Log();
????????t3.move();
????}
}
?
?
三、运行结果
			
		
?
?
四、小结
			
凡是要求灵活多变的功能,多数用接口多态实现
			
?
?
组合方式实现代理的缺点:每实现一个需求都需要写一个代理类,比如:为了实现在方法前后加日志TankLogProxy、为了实现记录方法运行时间TankTimeProxy,随着系统的复杂,如果还需要实现权限、事务管理,用这种设计方法,代理类会越来越多。有没有一种方式,能够让我们不写这些代理类? 动态代理,动态的去代理,代理类是动态生成的,不需要我们编写,这样就可以解决这个代理类很多的问题,这样会极大地减少了我们的工作。
?
?
?
?
?
代理模式-动态代理 调用Proxy.newProxyInstance()
http://www.cnblogs.com/shamgod/p/4592014.html
	
一、概述
			
1.目标:不自己写代理类,利用Proxy.newProxyInstance()动态生成
			
2.用到的知识点:
			
(1)//编译源码,生成class,注意编译环境要换成jdk1.6才有compiler,单纯的jre没有compiler,会空指针错误
			
JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
(2)//文件管事器
StandardJavaFileManager fileMgr = jc.getStandardFileManager(null, null, null);
(3)//编译单元
Iterable units = fileMgr.getJavaFileObjects(file);
(4)//编译任务
CompilationTask t = jc.getTask(null, fileMgr, null, null, null, units);
(5)//编译
t.call();
			
(6)//把类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");
		
(7)//生成实例
			
//return c.newInstance(); //c.newInstance()会调用无参数的Construtor,若类没有无参的Constructor时会出错
Constructor ctr = c.getConstructor(Movable.class);
return ctr.newInstance(new Tank());
			
?
?
二、代码
			
1.Movable.java
		
2.Tank.java
		
3.Proxy.java
		
4.Client.java
		
?1.Moveable.java
		
package com.weiqinshian.proxy;
public
					interface Moveable
{
???public
					void move();
}
?
2.Tank.java
		
package com.weiqinshian.proxy;
import java.util.Random;
public
					class Tank implements Moveable
{
???@Override
???public
					void move()
???{
??????System.out.println("tank move........");
??????try
				
??????{
?????????Thread.sleep(new Random().nextInt(10000));
??????} catch (InterruptedException e)
??????{
?????????e.printStackTrace();
??????}
???}
}
?
3.Proxy.java
		
package com.weiqinshian.proxy;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
public
					class Proxy
{
???public
					static Object newProxyInstance() throws Exception
???{
??????String rt = "\n\r";
??????// 动态代理文件的源码
				
??????String str = "package com.weiqinshian.proxy;" + rt +
??????"public class TankTimeProxy implements Moveable {" + rt +
??????"private Moveable m;" + rt +
??????"public TankTimeProxy(Moveable m) {" + rt + "this.m = m;" + rt + "}" + rt +
??????"@Override" + rt + "public void move() {" + rt + "System.out.println(\"Time Proxy start...........\");" + rt + "long start = System.currentTimeMillis();" + rt + "m.move();" + rt
????????????+ "long end = System.currentTimeMillis();" + rt + "System.out.println(\"花费时间:\"+(end - start));" + rt + "System.out.println(\"Time Proxy end...........\");" + rt + "}" + rt +
????????????"}";
??????// 把源码写到java文件里
				
??????File file = new File("d:/src/com/weiqinshian/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到内存里src\com\weiqinshian\proxy
				
??????URL[] urls = new URL[]
??????{ new URL("file:/" + "d:/src/") };
??????System.out.println("file:/" + System.getProperty("user.dir") + "/src/com/weiqinshian/proxy/TankTimeProxy.class");
??????URLClassLoader uc = new URLClassLoader(urls);
??????Class c = uc.loadClass("com.weiqinshian.proxy.TankTimeProxy");
??????// 生成实例
				
??????// return c.newInstance();
				
??????// //c.newInstance()会调用无参数的Construtor,若类没有无参的Constructor时会出错
				
??????Constructor ctr = c.getConstructor(Moveable.class);
??????return ctr.newInstance(new Tank());
???}
}
?
?
4.Client.java
		
?package com.weiqinshian.proxy;
				
public
					class Client
{
???public
					static
					void main(String[] args) throws Exception
???{
??????Moveable m = (Moveable) Proxy.newProxyInstance();
??????m.move();// 感觉没有生成任何代理类
				
???}
}
三、运行结果
			
		
?
?
这种方式存在的问题:现在动态代理,动态生成的代理类是写死了的,是用字符串写死在类里面的,而且,只能动态生成实现了 Moveable接口的代理,如果要实现任意接口的代理应该怎么办? 那就不将动态生成代理类的字符串写死,动态拼接生成代理类。 
		
代理模式--动态代理 修改成可以代理任意接口
?
一、概述
			
1.目标:把Proxy修改成可以代理任意接口及其任意方法,只要传接口名给newProxyInstance,就能动态生成实现了该接口的代理类。
			
2.思路:
			
(1)代理任意接口:把接口类型作为参数传给Proxy的newProxyInstance(Class interfze)
			
(2)代理任意方法:用interfze.getMethods()取出所有方法,拼接实现方法的字符串
			
?
?
二、代码
			
1.Movable.java
		
2.Tank.java
		
3.Proxy.java
		
4.Client.java
		
?
?
1.Movable.java
		
package com.weiqinshian.proxy;
public
					interface Moveable
{
???public
					void move();
???public
					void stop();
}
?
?
2.Tank.java
		
package com.weiqinshian.proxy;
import java.util.Random;
public
					class Tank implements Moveable
{
???@Override
???public
					void move()
???{
??????System.out.println("tank move........");
??????try
				
??????{
?????????Thread.sleep(new Random().nextInt(10000));
??????} catch (InterruptedException e)
??????{
?????????e.printStackTrace();
??????}
???}
???public
					void stop()
???{
??????System.out.println("Tank stopping.......");
???}
}
?
3.Proxy.java
		
package com.weiqinshian.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.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
?
public
					class Proxy
{
???public
					static Object newProxyInstance(Class interfze) 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 + "System.out.println(\"Time Proxy start...........\");" + rt
???????????????+ "long start = System.currentTimeMillis();" + rt + "m." + m.getName() + "();" + rt + "long end = System.currentTimeMillis();" + rt
???????????????+ "System.out.println(\"花费时间:\"+(end - start));" + rt + "System.out.println(\"Time Proxy end...........\");" + rt + "}";
??????}
??????// 动态代理文件的源码
				
??????String str = "package com.weiqinshian.proxy; " + rt +
??????"public class TankTimeProxy implements " + interfze.getName() + " {" + rt +
??????"private " + interfze.getName() + " m;" + rt +
??????"public TankTimeProxy(" + interfze.getName() + " m) {" + rt + "this.m = m;" + rt + "}" + rt +
??????methodStr + rt +
??????"}";
??????// 把源码写到java文件里
				
??????File file = new File("d:/src/com/weiqinshian/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到内存里src\com\weiqinshian\proxy
				
??????URL[] urls = new URL[]
??????{ new URL("file:/" + "d:/src/") };
??????System.out.println("file:/" + System.getProperty("user.dir") + "/src/com/weiqinshian/proxy/TankTimeProxy.class");
??????URLClassLoader uc = new URLClassLoader(urls);
??????Class c = uc.loadClass("com.weiqinshian.proxy.TankTimeProxy");
??????// 生成实例
				
??????// return c.newInstance();
				
??????// //c.newInstance()会调用无参数的Construtor,若类没有无参的Constructor时会出错
				
??????Constructor ctr = c.getConstructor(interfze);
??????return ctr.newInstance(new Tank());
???}
}
?
?
4.Client.java
		
package com.weiqinshian.proxy;
?
public
					class Client
{
???public
					static
					void main(String[] args) throws Exception
???{
??????Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class);// 方法参数可以传任意接口类型
				
??????m.move();
??????m.stop();
???}
}
?
三、运行结果
			
		
?
?
代理模式-动态代理 修改成可以任意修改代理逻辑
一、概述
			
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//InvocationHandler ,代理的类型,调用的时候,你要告诉我,你想产生的是什么类型(日志、权限、时间)的代理
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 }
		
?
?
三、运行结果
			
		
Java-马士兵动态代理模式
标签:int   user   ssl   还需要   file   ace   dir   系统   net   
原文地址:http://www.cnblogs.com/weiqinshian/p/5997543.html