首页 > 编程 > Java > 正文

JAVA动态代理

2019-11-08 19:53:37
字体:
来源:转载
供稿:网友

java JDK动态代理

java JDK动态代理实现原理是用JDK6 Complier API实现的示例:模仿sPRing的AOPInvocationHandler.java
package com.bjsxt.proxy;import java.lang.reflect.Method;public interface InvocationHandler {	public void invoke(Object o, Method m);}Proxy.java
package com.bjsxt.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 infce, InvocationHandler h) throws Exception { //JDK6 Complier API, CGLib, ASM		String methodStr = "";		String rt = "/r/n";				Method[] methods = infce.getMethods();				for(Method m : methods) {			methodStr += "@Override" + rt + 						 "public void " + m.getName() + "() {" + rt +						 "    try {" + rt +						 "    Method md = " + infce.getName() + ".class.getMethod(/"" + m.getName() + "/");" + rt +						 "    h.invoke(this, md);" + rt +						 "    }catch(Exception e) {e.printStackTrace();}" + rt +												 "}";		}				String src = 			"package com.bjsxt.proxy;" +  rt +			"import java.lang.reflect.Method;" + rt +			"public class $Proxy1 implements " + infce.getName() + "{" + rt +			"    public $Proxy1(InvocationHandler h) {" + rt +			"        this.h = h;" + rt +			"    }" + rt +									"    com.bjsxt.proxy.InvocationHandler h;" + rt +										methodStr +			"}";		String fileName = 			"d:/src/com/bjsxt/proxy/$Proxy1.java";		File f = new File(fileName);		FileWriter fw = new FileWriter(f);		fw.write(src);		fw.flush();		fw.close();				//compile		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();		StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);		Iterable units = fileMgr.getJavaFileObjects(fileName);		CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);		t.call();		fileMgr.close();				//load into memory and create an instance		URL[] urls = new URL[] {new URL("file:/" + "d:/src/")};		URLClassLoader ul = new URLClassLoader(urls);		Class c = ul.loadClass("com.bjsxt.proxy.$Proxy1");		System.out.println(c);				Constructor ctr = c.getConstructor(InvocationHandler.class);		Object m = ctr.newInstance(h);		//m.move();		return m;	}}Proxy实现步骤:1.根据传过来的接口Class,遍历其中的方法(拼接使用InvocationHandler 调用方法的代码字符串),使用IO操作生成对应的java类文件2.根据步骤1生成的java类文件,使用JavaCompiler类将其编程成class3.使用URLClassLoader将class载入内存,调用class的构造方法实例化对象使用:Client.java
public class Client {	public static void main(String[] args) throws Exception {		Tank t = new Tank();		InvocationHandler h = new TimeHandler(t);				Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class, h);				m.move();	}}

CGLIB 和 JDK生成动态代理类

区别:JDK动态代理只能对实现了接口的类生成代理,而不能针对类 CGLIB是针对类实现代理,其原理是通过字节码技术为一个类创建子类,主要是对指定的类生成一个子类,覆盖其中的方法 ,因为是继承,所以该类或方法最好不要声明成final springAOP 使用的设计模式就是动态代理模式。如果目标对象实现了接口,则spring使用jdk 动态代理技术,如果目标对象没有实现接口,则spring使用CGLIB技术。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表