jdk动态代理原理

动态代理实现思路:

Moveable m = (Moveable) Proxy.newProxyInstance(ClassLoader, Interfaces, InvocationHandler);

 实现功能:通过Proxy的newProxyInstance返回代理对象
                   * 1.声明一段源码(动态产生代理)
                   * 2.编译源码(JDK Compiler API),产生新的类(代理类)
                   * 3.将这个类load到内存当中,产生一个新的对象(代理对象)
                   * 4.return 代理对象
 
 由于对实现接口的任意对象的任意方法进行代理

1.Proxy.java:

package com.zy.proxyPrinciple;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;

import org.apache.commons.io.FileUtils;

public class Proxy {

	public static Object newProxyInstance(Class infce) throws Exception {

		// windows下的换行符
		String rt = "\r\n";

		//获取类中的所有方法
		String methodStr = "";
		for (Method m : infce.getMethods()) {
			methodStr += 
					"@Override"+ rt+ 
					"public void "+m.getName()+"() {"+ rt+ 
					"long starttime = System.currentTimeMillis();"+ rt+ 
					"System.out.println(\"汽车开始行驶...\");"+ rt+ 
					"m."+m.getName()+"();"+ rt+ 
					"long endtime = System.currentTimeMillis();"+ rt+ 
					"System.out.println(\"汽车结束行使..\" + (endtime - starttime) + \"毫秒\");"+ rt +
					"}" ;
		}
		
		// 源码
		// 返回的动态代理类(CarTimeProxy.java),注意"要用转义字符\,每行末尾加rt换行,jdk生成代理类、构造函数名字为$Proxy0
		String str =

		"package com.zy.proxyPrinciple;"+ rt+

				"public class $Proxy0 implements "+infce.getName()+" {"+ rt+

				"public $Proxy0("+infce.getName()+" m) {"+ rt+ 
				"super();"+ rt+
                "this.m = m;"+ rt+ 
                "}"+ rt+

				"private "+infce.getName()+" m;"+ rt+
			     methodStr + rt +
				"}";

		// 先创建java文件放置到对应的文件目录,再编译此java文件
		// 获得当前的路径
		// 放在bin目录下方便编译
		String filename = System.getProperty("user.dir")
				+ "/bin/com/zy/proxyPrinciple/$Proxy.java";
		File file = new File(filename);

		// 引入jar包,commons-io.jar,提供FileUtils快速写入内容到文件中
		FileUtils.writeStringToFile(file, str);

		return null;
	}
}

2.Test.java:

package com.zy.proxyPrinciple;

public class Test {

	public static void main(String[] args) throws Exception {

		Proxy.newProxyInstance(Moveable.class);

	}

}

3.将代理业务抽取出来对任意对象的任意方法起作用,动态的实现业务逻辑
   创建事务处理器:


  1> InvocationHandler.java接口:

package com.zy.proxyPrinciple;

import java.lang.reflect.Method;

public interface InvocationHandler {

	public void invoke(Object o, Method m);
}

  2>TimeHandler.java接口实现类:(把Proxy.java中写死的业务代码提取到相应的业务处理类)

package com.zy.proxyPrinciple;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TimeHandler implements InvocationHandler {

	// 获取被代理类
	private Object target;

	public TimeHandler(Object target) {
		super();
		this.target = target;
	}

	@Override
	public void invoke(Object o, Method m) {

		try {
			long starttime = System.currentTimeMillis();
			System.out.println("汽车开始行驶...");
			// 调用代理类的方法
			m.invoke(target);
			long endtime = System.currentTimeMillis();
			System.out.println("汽车结束行使.." + (endtime - starttime) + "毫秒");
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

  3>修改Proxy.java,将代理业务处理类作为参数传入代理对象
       源码中创建InvocationHandler,并且import进来,import Method进来


package com.zy.proxyPrinciple;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

import org.apache.commons.io.FileUtils;

public class Proxy {

	public static Object newProxyInstance(Class infce,<span style="color:#ff6666;">InvocationHandler h</span>) throws Exception {

		// windows下的换行符
		String rt = "\r\n";

		//获取类中的所有方法
		String methodStr = "";
		for (Method m : infce.getMethods()) {
			methodStr += "@Override"+ rt+ 
					"public void "+m.getName()+"() {"+ rt+ 
					"try{"+ rt+ 
					<span style="color:#ff6666;">"Method md = "+infce.getName() +".class.getMethod(\""
					            +m.getName()+"\");"+ rt+ 
					"h.invoke(this,md);"+ rt+</span>
					"}catch(Exception e){e.printStackTrace();}"+ rt+
					"}" ;
		}
		
		// 源码
		// 返回的动态代理类(CarTimeProxy.java),注意"要用转义字符\,每行末尾加rt换行,jdk生成代理类、构造函数名字为$Proxy0
		String str =
		"package com.zy.proxyPrinciple;"+ rt+
<span style="color:#ff6666;">		"import com.zy.proxyPrinciple.InvocationHandler;"+ rt+
                "import java.lang.reflect.Method;"+ rt+</span>
				"public class $Proxy0 implements "+infce.getName()+" {"+ rt+

				"public $Proxy0(InvocationHandler h) {"+ rt+ 
				"super();"+ rt+
                                "this.h = h;"+ rt+ 
                "}"+ rt+
<span style="color:#ff6666;">				"private InvocationHandler h;"+ rt+</span>
			         methodStr + rt +
				"}";

		// 1、产生代理类的java文件
		// 获得当前的路径
		// 放在bin目录下方便编译
		String filename = System.getProperty("user.dir")
				+ "/bin/com/zy/proxyPrinciple/$Proxy0.java";
		File file = new File(filename);
		// 引入jar包,commons-io.jar,提供FileUtils快速写入内容到文件中
		FileUtils.writeStringToFile(file, str);
		
		//2、编译代理类的java文件
		//拿到编译器
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
		//文件管理者
		StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,null,null);
		//获取文件
		Iterable utils = fileMgr.getJavaFileObjects(filename);
		//编译任务
		//参数:输出位置,fileMgr,监听器,国际化参数,国际化参数,要编译的文件
		CompilationTask t = compiler.getTask(null,fileMgr,null,null,null,utils);
		//进行编译
		t.call();
		fileMgr.close();
		
		//3、编译好的文件load到内存中
		ClassLoader cl = ClassLoader.getSystemClassLoader();
		Class c = cl.loadClass("com.zy.proxyPrinciple.$Proxy0"); 
		
                //4、根据代理类的构造方法创建代理类并返回
		Constructor ctr = c.getConstructor(<span style="color:#ff6666;">InvocationHandler.class</span>);
<span style="color:#ff6666;">		return ctr.newInstance(h);</span>
		
	}
}

  4>测试类:Test.java

package com.zy.proxyPrinciple;

public class Test {

	public static void main(String[] args) throws Exception {

		Car car = new Car();
		InvocationHandler h = new TimeHandler(car);
		Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class, h);
		m.move();
	}

}



具体思路:

Proxy.java:声明动态源码,产生动态代理 --> 源码生成java文件 --> 对java文件进行编译 --> 将编译好的java文件load到内存中 --> 产生代理类的对象 

Test.java: 定义一个InvocationHandler专门进行代理业务处理(计时功能、日志功能等) --> 产生代理对象时把InvocationHandler传进去
           
面向切面编程(InvocationHandler): 在方法的前后增加逻辑处理


  



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值