在网上自学了下Java的代理,把贴出来代码做个笔记和总结
一、使用代理的目的
1、路由对远程服务器的方法调用
2、在程序运行期间,将用户接口事件和动作关联起来
3、为调试、跟踪方法调用等等
二、实现代理需要的类和接口包括:
1、用来生成代理类的Proxy类
2、被代理的类需要实现的接口,这里用的Moveable
3、调用处理器接口InvocationHandler
4、具体的被代理的类,这里是Tank,它实现Mobeable接口
5、实现调用处理器接口的包装器类,这里是TimeHandler
三、代理类是在Proxy类中动态生成,且必须要实现被代理类所实现的接口,代理类具有的方法有:
1、指定接口所需要的全部方法,这里是Moveable
2、Object类中的全部方法,例如:toString(),equals()等,因为Object是所有类的超类
下面的例子这里要实现的代理逻辑是,Tank类在每次调用move()方法之前和之后都记录一下当前的时间
首先是测试类
package proxy;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
public class ProxyTest {
public static void main(String[] args) throws SecurityException, IllegalArgumentException, IOException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Tank t=new Tank();
InvocationHandler h=new TimeHandler(t);
Moveable m=(Moveable) Proxy.newProxyInstance(Moveable.class,h);
m.move();
}
}
被代理类的接口
package proxy;
public interface Moveable {
public void move();
}
被代理的类
package proxy;
public class Tank implements Moveable{
@Override
public void move() {
Thread t=new Thread();
t.start();
try {
t.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("moving...");
}
时间处理的包装器,构造函数需要传递被代理的对象
package proxy;
import java.lang.reflect.Method;
import java.util.Date;
public class TimeHandler implements InvocationHandler {
Object target;
public TimeHandler(Object target){
super();
this.target=target;
}
@Override
public void invoke(Object o,Method m) {
System.out.println("start time:"+new Date().toLocaleString());
try{
m.invoke(target);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("end time:"+new Date().toLocaleString());
}
}
最重要的Proxy
package proxy;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.;
public class Proxy {
public static Object newProxyInstance(Class intrfc,InvocationHandler h) throws IOException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
String mthStr="";//用来保存从intrfc中继承而来的所有方法的详细实现
Method[] methods=intrfc.getMethods();//用来保存intrfc的所有方法名
for(Method m:methods){
mthStr+="@Override" +" "
+ "public void "+m.getName()+"(){"+
"try{"+
"Method md="+intrfc.getName()+".class.getMethod(\""+m.getName()+"\");"+
"h.invoke(this,md);"+
"}catch(Exception e){"+
"}"+
"}";
}
String str ="import java.lang.reflect.Method;"
+ "public class MyProxy implements "+ intrfc.getName()+"{"
+ "proxy.InvocationHandler h;"
+"public MyProxy(proxy.InvocationHandler h ){"
+ "this.h=h;"
+ "}"
+mthStr
+"}";
String fileName ="D:/Workspaces/Eclipse/DesignPattern/src//MyProxy.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(str);
fw.flush();
fw.close();
//compile
JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr=compiler.getStandardFileManager(null, null, null);
Iterable units=fileMgr.getJavaFileObjects(fileName);
CompilationTask task=compiler.getTask(null, fileMgr, null,null,null,units);
task.call();
fileMgr.close();
//load进入内存
URL[] urls = new URL[] {new URL("file:/" + "D:/Workspaces/Eclipse/DesignPattern/src/")};
URLClassLoader ul = new URLClassLoader(urls);
Class c=ul.loadClass("MyProxy");
//通过Class实例创建的对象必须含有默认构造函数,
//TimepProxy类当中不含有默认构造函数,所以只能通过
//Constructor的实例来创建对象
Constructor ctr=c.getConstructor(InvocationHandler.class);
Object m=ctr.newInstance(h);
return m;
}
}
关于代理类实现的核心部分
1、代理类只包含一个调用处理器的实例InvocationHandler h;
2、代理类实现了被代理类所实现的接口当中的所有方法,并将实现的细节交给了调用处理器h.invoke(this,md);
3、通过编译、类加载器等技术得到代理类的Class对象
4、通过Proxy.newProxyInstance()传递进来的调用处理器对象赋值给代理类并构造代理对象
5、将创建的代理对象返回给客户