您的位置:首页 > 编程语言 > Java开发

[Java] 动态代理 05 一个成功程序的例子, 改变几句就成了另一个功能

2014-01-23 11:50 597 查看
com.bjsxt.proxy

InvocationHandler

package com.bjsxt.proxy;

import java.lang.reflect.Method;

public interface InvocationHandler { //指定方法(你需要时间,日志,还是其他)
public void invoke(Object o,Method m);//告诉那个对象去执行这个方法
}
Proxy   这个类的作用就是用来产生新的代理类  
package com.bjsxt.proxy;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

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

import java.net.URL;
import java.net.URLClassLoader;

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

import com.bjsxt.proxy.Moveable;
import com.bjsxt.proxy.Tank;

public class Proxy {
// 这个类的作用就是用来产生新的代理类
public static Object newProxyInstance(Class infce, InvocationHandler h)
throws IOException, ClassNotFoundException, SecurityException,
NoSuchMethodException, IllegalArgumentException,
InstantiationException, IllegalAccessException,
InvocationTargetException { // JDK6 Complier
// API, CGLib,
// ASM
/*
* 把这个类当成一个string的字符串(源码) 现在我们假设,我们能把这字符串编译,生成类,放在内存,来产生对象
*
* 动态代理就是你看不到代理类,你只需要调用一个方法( Proxy的newProxyInstance()方法),
* 会自动给你返回一个代理类对象,这个对象的产生是由内部动态的生成一段代码,编译完成的
*/
String methodStr = "";
String rt = "\r\n";

Method ms[] = infce.getMethods();
/*
* for (Method m : ms) { methodStr = "@Override" + rt +
* "    public void " + m.getName() + "() {" + rt +
* "        long start = System.currentTimeMillis();" + rt +
* "        t." + m.getName() + "();" + rt +
* "        long end = System.currentTimeMillis();" + rt +
* "        System.out.println((end - start));" + rt + "    }"; }
*/
for (Method m : ms) {
methodStr = 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) {" + rt
+ "    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 + rt
+ "    com.bjsxt.proxy.InvocationHandler h;" + rt + methodStr
+ rt + "}";
// 获取当前系统目录(就是项目根目录)
String fileName = "d:/src/com/bjsxt/proxy/$Proxy1.java";
System.out.println(fileName);

// System.out.println(fileName);
File f = new File(fileName);
FileWriter writer = new FileWriter(f);
writer.write(src);
writer.flush();
writer.close();
// 看是否生成代码,右键项目,刷新就OK了
/*
* 第三步 : 我们来生成一个类
*/
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // 拿到java的编译器

System.out.println(compiler.getClass().getName());

StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,
null, null);// 文件的 管理器

Iterable untis = fileMgr.getJavaFileObjects(fileName); // 找到文件,把文件放在
// Iterable(数组)中

CompilationTask t = compiler.getTask(null, fileMgr, null, null, null,
untis);// 定好编译文件任务
t.call(); // 编译文件

fileMgr.close();// 关闭文件管理器
/*
* 运行 :
* 编译之后,打开Navigator(这个可以看到类详细的变化,就是看得到class文件的产生),就会看到多了一个$Proxy1
* .class 文件,第三步成功
*/
// Load into memory and create an instance
/*
* 第四步: 我们把文件加入内存(原本一般的做法是class.loader,就OK了,但是调用这个方法的前提就是,
* 你的class文件目录必须在classpath的文件目录下),我们这里用一种通用的做法
*/
// 这里使用url加载器
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);
// 测试:输出c,OK,第四步完成
// 最后一步,生成对象
// 反射来创建对象
Constructor ctr = c.getConstructor(InvocationHandler.class); // 获取构造方法

Object m = (Object) ctr.newInstance(h);
// m.move();
return m;
}
}
com.bjsxt.proxy.test

UserMgr   interface          抽象主题角色

package com.bjsxt.proxy.test;

public interface UserMgr {
void addUser();
}
UserMgrImpl           实际被代理对象
package com.bjsxt.proxy.test;

public class UserMgrImpl implements UserMgr {

@Override
public void addUser() {
System.out.println("1.:  插入记录到user表");
System.out.println("2.: 做日志在另外一张表");

}
}
TransactionHandler
   代理主题角色
package com.bjsxt.proxy.test;

import java.lang.reflect.Method;

import com.bjsxt.proxy.InvocationHandler;

public class TransactionHandler implements InvocationHandler {

private Object target; // 被代理对象

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

}
Client
package com.bjsxt.proxy.test;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

import com.bjsxt.proxy.InvocationHandler;
import com.bjsxt.proxy.Moveable;
import com.bjsxt.proxy.Proxy;
import com.bjsxt.proxy.TimeHandler;

public class Client {
public static void main(String[] args) throws Exception {
UserMgr mgr = new UserMgrImpl();
InvocationHandler h = new TransactionHandler(mgr);
UserMgr m = (UserMgr) Proxy.newProxyInstance(UserMgr.class, h);
m.addUser();

}

}
运行输出
d:/src/com/bjsxt/proxy/$Proxy1.java
com.sun.tools.javac.api.JavacTool
class com.bjsxt.proxy.$Proxy1
Transaction Start
1.:  插入记录到user表
2.: 做日志在另外一张表
Transaction Commit




 
                
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: