设计模式 --> 代理模式(二)(源码模拟改进)

    对上一文中动态代理的优化:
一、动态生成接口
    只需要在使用 Proxy.newProxyInstance() 方法时,将接口作为形参传入,做如下更改即可:
1、改变形参,调用接口的名字。

2、调用时写入要调用的接口名。 


扩展接口名很简单,只需要加入要调用的接口名即可。之后的问题是:在这里,只能用 move() 方法,如何对它进行动态生成呢?

二、动态生成方法
将要进行修改的方法进行提取,并对其进行修改。
methodStr 编写方法块,写入 str 

在最后


新问题:现在生成的代理,只能生成时间的代理。那么如何改进。
三、产生其他处理方式的代理,调用一个别人指定的处理方式。
(InvocationHandler:方法调用的处理器)
1、该处理器应该有一个 method ,来处理任何方法。而处理的方式,由子类来决定,子类可以灵活的采取处理方法,日志记录,权限设置等。

记录时间的子类


2、产生什么样类型的代理,进行何种的处理 newProxyInstance3(Class infc, InvocationHandler handle)
------------------------------------------------------------------------------------
public static Object newProxyInstance3(Class infc, InvocationHandler handler) throws Exception{
		String rt = "\r\n";
		String methodStr = "";	
		Method[] methods = infc.getMethods();
		for(Method m : methods){
			methodStr += "	@Override " + rt +
					 	 "	public void " + m.getName() + "()" + "{" + rt +
					 	 " 		try {" + rt +
						 "			   Method md = " + infc.getName()  + ".class.getMethod(\"" + m.getName() + "\");	"+ rt +
						 "			   h.invock(this, md);" + rt + ""+ 
						 "          } catch(Exception e){e.printStackTrace();}" + rt + 
						 "  }" + rt +
						 "}";
			System.out.println("methodStr === " + methodStr);
		}	
		String str = 
				"package com.inspur.simpleProxy;" + rt +
				"import java.lang.reflect.Method;" + rt +
				
				"public class TankTimeProxy implements " + infc.getName() + "{" + rt +
				
				" 	com.inspur.simpleProxy.InvocationHandler h;" + rt + 
				
				"	public TankTimeProxy(InvocationHandler handler){" + rt +
				"		this.h = handler;" + rt +
				"	}" + rt +
				
				 	methodStr;
		/*
		 * 要生成的目的地
		 */
		String fileName = System.getProperty("user.dir") + "/src/com/inspur/simpleProxy/TankTimeProxy.java";
		File file = new File(fileName);
		FileWriter fileWriter = new FileWriter(file);
		fileWriter.write(str);
		fileWriter.flush();
		fileWriter.close();
		
		/*
		 * 编译,生成 .class 文件
		 */
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
		System.out.println(compiler.getClass().getName());
		StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
		Iterable iterable = fileManager.getJavaFileObjects(fileName);
		CompilationTask task = compiler.getTask(null, fileManager, null, null, null, iterable);
		task.call();
		fileManager.close();
		
		/*
		 * load to memory , create an instance
		 * 加载到内存,生成新对象
		 */
		// 将硬盘上的 Java 文件,放到内存中的类中,需要指定路径
		// 此方式还可以从网上去 load 类,通过网络传来的类 , 也可以通过此方式来 load 类
		// user.dir 当前文件根目录
		
		URL[] urls = new URL[]{new URL("file:/" + System.getProperty("user.dir") + "/src")};
		URLClassLoader urlClassLoader = new URLClassLoader(urls);
		Class c = urlClassLoader.loadClass("com.inspur.simpleProxy.TankTimeProxy");
		System.out.println(c);

		// 拿到其中的构造方法,得到方法,通过参数来确定。  找一个构造方法,这个构造方法的参数类型是 Moveable ,便得到了 TankTimeProxy
		Constructor constructor = c.getConstructor(InvocationHandler.class);
		//Object m = constructor.newInstance(new Tank());
		//m.move();
		// c.newInstance(); 会产生一个新的构造方法
//		Moveable m = (Moveable) constructor.newInstance(new Tank());
//		return m;
		
		// 因为我们并不知道 infc 实现的是哪个接口,将新生成的对象作为 Object 类型的返回值 返回回去
		Object m = constructor.newInstance(handler);
		return m;
	}


------------------------------------------------------------------------------------
3、Client 类



一个典型的动态代理创建对象过程可分为以下四个步骤:
1、通过实现 InvocationHandler 接口创建自己的调用处理器, 
InvocationHandler handler = new InvocationHandler( ... );
2、通过为 Proxy 类指定 ClassLoader 对象和一组 interface 创建动态代理类

Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});

3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型

Constructor constructor = clazz.getConstructor(

                                new Class[]{InvocationHandler.class});

4、通过构造函数创建代理类实例,此时需要将处理器对象作为参数被传入

Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));

为了简化对象的创建过程,Proxy 类中的 newInstance 方法封装了 2 -- 4,只需要两步即可完成代理对象的创建。
生成的 ProxySubject 继承 Proxy 类实现 Subject 接口,实现的 Subject 的方法实际调用处理器的 invoke 方法,而 invoke 犯法利用反射调用的是被代理对象的方法

Object result=method.invoke( proxied,args );


通过 java.lang.reflect 包下的方法实现动态代理

1、编写接口


2、编写委托类


3、编写处理类,实现 InvocationHandler 接口,实现记录的功能


4、编写 Client 类



上面的 Proxy 类是对类 $Proxy0 类的模拟,此类完成的功能是:

-- 动态生成代理对象

-- 将代理对象进行编译,得到 .class 文件,即 代理对象.class

-- 加载到内存

-- 通过构造方法,得到要调用的对应的方法

(以上是个人理解,自觉无法言明,在网上搜罗信息时发现此博主的文章甚是有理,请大家查看下一篇文章 -- 动态代理深入分析(一)(二))


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值