动态反射代理实现机制两例代码比较,最近研究设计模式,略作深入分析基于JDK1.3以来的Java动态反射代理,也结合最新的JDK1.6版本以上的新特性进行比较,业界主要有CGLIB、ASM等技术实现生成字节码。
通常我们使用反射代理这种统一处理方式针对一致日志、事务、权限、监控、拦截等这种具有切面点的场景进行一系列的自动处理,减轻程序员的代码编写量,提升代码的耦合度,适当提升代码编写质量,对系统架构的扩展性进一步加强。此处放在这里做一个参考比较,学习使用,抛砖引玉,以资共享......
由于时间紧迫,先写一个简单日后再完善......
第二种实现代码如下(基于JDK1.6以上的自带新特性):
被代理方法的接口类 Vehicleable.java:
/**
* @author Dennis Zhao
* @createdTime:Mar 29, 2013
*/
public interface Vehicleable extends java.io.Serializable {
void run();
void run(Car car);
void run(Car car, MotoCar c);
}
被代理方法的接口实现类 Vehicle.java:
import java.util.Random;
/**
* @author Dennis Zhao
* @createdTime:Mar 29, 2013
*/
public class Vehicle implements Vehicleable {
private static final long serialVersionUID = 7633089691765059657L;
@Override
public void run() {
System.out.println("Automatic Moving...");
try {
Thread.sleep(new Random().nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run(Car car) {
String name = Car.class.getName();
System.out.println(name.substring(name.lastIndexOf(".") + 1) + " Moving...");
System.out.println("car name == " + car.getName() );
System.out.println("car color == " + car.getColor() );
System.out.println("car age == " + car.getAge() );
try {
Thread.sleep(new Random().nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run(Car car, MotoCar c) {
String name = Car.class.getName();
String name1 = MotoCar.class.getName();
System.out.println(name.substring(name.lastIndexOf(".") + 1)
+ " and " + name1.substring(name1.lastIndexOf(".") + 1) + " Moving...");
System.out.println("car name == " + car.getName() );
System.out.println("car color == " + car.getColor() );
System.out.println("car age == " + car.getAge() );
System.out.println("motocar color == " + c.getColor() );
System.out.println("motocar name == " + c.getName() );
System.out.println("motocar age == " + c.getAge() );
try {
Thread.sleep(new Random().nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
提供两个测试用的Javabea类Car.java, MotoCar.java
/**
* @author Dennis Zhao
* @createdTime:Mar 29, 2013
*/
public class Car implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String color;
private int age;
public String getName() {
return name;
}
public Car setName(String name) {
this.name = name;
return this;
}
public String getColor() {
return color;
}
public Car setColor(String color) {
this.color = color;
return this;
}
public int getAge() {
return age;
}
public Car setAge(int age) {
this.age = age;
return this;
}
}
MotoCar.java
/**
* @author Dennis Zhao
* @createdTime:Mar 29, 2013
*/
public class MotoCar implements java.io.Serializable {
private static final long serialVersionUID = 11L;
private String name;
private String color;
private int age;
public String getName() {
return name;
}
public MotoCar setName(String name) {
this.name = name;
return this;
}
public String getColor() {
return color;
}
public MotoCar setColor(String color) {
this.color = color;
return this;
}
public int getAge() {
return age;
}
public MotoCar setAge(int age) {
this.age = age;
return this;
}
}
自定义一个模拟JDK接口类InvocationHandler.java
/**
* 模拟 JDK InvocationHandler处理类
* @author Dennis Zhao
* @createdTime:Mar 29, 2013
*/
public interface InvocationHandler extends java.io.Serializable {
public void invoke(Object o, Method m, Object... obj);
}
接口类InvocationHandler的实现类LogHandler.java
import java.lang.reflect.Method;
/**
* 模拟日志包装处理类
* @author Dennis Zhao
* @createdTime:Mar 29, 2013
*/
public class LogHandler implements InvocationHandler{
private static final long serialVersionUID = -9124608101609510202L;
private Object target;
public LogHandler(Object target) {
super();
this.target = target;
}
@Override
public void invoke(Object o, Method m, Object... obj) {
long start = System.currentTimeMillis();
System.out.println("正式的方法 log :" + start);
//System.out.println(o.getClass().getName());
try {
m.invoke(target, obj);
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("运行 时间 log :" + (end-start));
}
}
生成隐藏动态代理类HiddenProxy.java
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;
/**
* 隐藏代理类,完全动态生成执行,自定义代码
* @author Dennis Zhao
* @createdTime:Mar 29, 2013
*/
public class HiddenProxy {
@SuppressWarnings("unchecked")
public static Object newProxyInstance(Class<?> interfaces, InvocationHandler h) throws Exception {
StringBuffer methodStr = new StringBuffer("");
String newLine = "\r\n";
String curPath = System.getProperty("user.dir");
String filePath = curPath + File.separator + "tmp" + File.separator;
Method[] methods = interfaces.getMethods();
for(Method m : methods) {
StringBuffer sb = new StringBuffer("");m.getParameterTypes();
StringBuffer sbp = new StringBuffer("");
Class[] cs = m.getParameterTypes();
for (Class c : cs) {
String objName = c.getName();
sb.append(objName).append(" ")
.append(objName.substring(objName.lastIndexOf(".") + 1).toLowerCase())
.append(",");
sbp.append(sb.substring(sb.lastIndexOf(" ")+1));
}
String strParam = "";
String param = "";
if(sb.length() > 0) {
strParam = sb.substring(0, sb.length() - 1);
param = "new Object[]{"+ sbp.substring(0, sbp.length() - 1) + "}";
} else {
param = "new Object[]{}";
}
int len = m.getParameterTypes().length;
methodStr.append(newLine).append(" @Override").append(newLine)
.append(" public void " + m.getName() + "(" + strParam + ") {" + newLine)
.append(" try {" + newLine )
.append(" System.out.println(\"自定义事务开始...\");" + newLine)
.append(" Method[] mds = " + interfaces.getName() + ".class.getMethods();").append(newLine)
.append(" for(Method m : mds) {").append(newLine)
.append(" if (m.getName().startsWith(\"" + m.getName() + "\") && ")
.append( len+"==m.getParameterTypes().length) {").append(newLine)
.append(" h.invoke(this, m, " + param + ");").append(newLine)
.append(" break;").append(newLine)
.append(" }").append(newLine)
.append(" }").append(newLine)
.append( newLine )
.append(" System.out.println(\"自定义事务完毕。 \" );" + newLine )
.append(" } catch(Exception e) {").append(newLine)
.append(" e.printStackTrace();" + newLine )
.append(" }" + newLine )
.append(" }" + newLine) ;
}
StringBuffer src = new StringBuffer().append(
"package com.pattern.proxy.aop.proxy;" + newLine)
.append("import java.lang.reflect.Method;" + newLine)
.append("import com.pattern.proxy.aop.proxy.InvocationHandler;" + newLine)
.append("public class MyProxy implements " + interfaces.getName() + "{" + newLine)
.append(" InvocationHandler h;" + newLine)
.append(" public MyProxy(InvocationHandler h) {" + newLine )
.append(" this.h = h;" + newLine )
.append(" }" + newLine )
.append(methodStr + newLine )
.append("}");
String fileName = filePath + "com" + File.separator +"pattern" + File.separator
+ "proxy" + File.separator +"aop" + File.separator +"proxy" + File.separator;
File f = new File(fileName);
f.mkdirs();
fileName = fileName + "MyProxy.java";
File f1 = new File(fileName);
FileWriter fw = new FileWriter(f1);
fw.write(src.toString());
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://" + filePath)};
URLClassLoader ul = new URLClassLoader(urls);
Class<?> c = ul.loadClass("com.pattern.proxy.aop.proxy.MyProxy");
Constructor<?> ctr = c.getConstructor(InvocationHandler.class);
Object m = ctr.newInstance(h);
//System.out.println(m.getClass().getName());
return m;
}
}
最后测试类以及测试结果Test.java
/**
* AOP模拟实现动态反射代理机制,基于 JDK1.6以上
* @author Dennis zhaoxiaobo
* @createdTime:Mar 29, 2013
*/
public class Test {
public static void main(String[] args) throws Exception {
Vehicle t = new Vehicle();
InvocationHandler h = new LogHandler(t);
Vehicleable m = (Vehicleable)HiddenProxy.newProxyInstance(Vehicleable.class, h);
m.run();
m.run(new Car().setName("abo car").setAge(12).setColor("black"));
m.run(new Car().setName("my car").setAge(11).setColor("red"),
new MotoCar().setColor("green").setName("Abo's motocar").setAge(100));
}
}
可以对任意的对象、任意的接口方法,实现任意的代理, 针对对象,注意(不支持基本数据类型)
/*
------------ 打印测试结果--------------
自定义事务开始...
正式的方法 log :1364539212298
Automatic Moving...
运行 时间 log :62
自定义事务完毕。
自定义事务开始...
正式的方法 log :1364539212360
Car Moving...
car name == abo car
car color == black
car age == 12
运行 时间 log :78
自定义事务完毕。
自定义事务开始...
正式的方法 log :1364539212438
Car and MotoCar Moving...
car name == my car
car color == red
car age == 11
motocar color == green
motocar name == Abo's motocar
motocar age == 100
运行 时间 log :110
自定义事务完毕。
*/
指定生成了虚拟的Java类,帮我们做一些本应该由代理类来完成的工作。
由于工作事情多,有时间再整理做一些文字性补充说明.....^_^