proxy:动态代理

        之前一直对动态代理这块比较模糊,因为不清楚它是如何动态在内存中产生及消失的,这2天通过对马士兵讲的动态代理的学习,现在终于有了个清晰的概念.

       Spring的AOP对动态代理这块有着巨大的应用,我就简单总结下,然后通过模拟JDK1.6中的Proxy.newProxyInstance(...,...,...)与invocationHandler.invoke(...,...,...)这2个接口中的方法来彻底理清它的动态方式.

       动态代理主要是解决类太多,相同功能的代码冗余以及功能重复利用的问题.它可以对任意的对象,任意的接口方法实现任意的代理,不用修改原来的代码,就可以在原来代码的基础上插入一些内容,而且这些新加的功能是可以叠加的,可插拔的(配置文件随便改功能).

       其实简单说起来,动态代理的实现就是通过方法内被拼字符串(其实就是拼类,像$Proxy1这种就是内部拼出来的),并将这些字符串保存在一个文件(cglib不用),通过JavaCompiler编译成class文件,最后再通过反射拿到这个对象,因为拼接是在方法内部执行的,所以方法执行完毕后,拼出来的这段代码就会销毁.因此每调用一次,就会拼一次,这样就实现了动态.

  以下为示例,其实完整写下来发现清晰很多

 

/**
 * 模拟接口InvocationHandler
*/
public interface InvocationHandler {
	public void invoke(Object o, Method m);
}

      

/**
 * 模拟类Proxy,看看它是如何拼字符串以及编译反射的
*/
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;
	}
}

下面开始写测试类测试

/**
  * 自定义的handler,主要用來模拟事物功能
*/
public class TransactionHandler implements InvocationHandler {
	
	private Object target;
	
	public TransactionHandler(Object target) {
		super();
		this.target = target;
	}

	@Override
	public void invoke(Object o, Method m) {
		System.out.println("Transaction Start");
		try {
			m.invoke(target);
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("Transaction Commit");
	}

}
/**
 *模拟service层:要给这个service层中的方法加事物功能
*/
public class UserMgrImpl implements UserMgr {

	@Override
	public void addUser() {
		System.out.println("1: 插入记录到user表");
		System.out.println("2: 做日志在另外一张表");
	}
	
}
/**
 * test测试
*/
public class Test{
	public static void main(String[] args) throws Exception {
		UserMgr mgr = new UserMgrImpl();
		InvocationHandler h = new TransactionHandler(mgr);
		UserMgr u = (UserMgr)Proxy.newProxyInstance(UserMgr.class,h);
		u.addUser();
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值