首页 > 代码库 > Java代理小结

Java代理小结

在网上自学了下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、将创建的代理对象返回给客户


Java代理小结