代理就跟IO中的装饰模式差不多,一个类代理另外一个类的意思就是保留原来类中对该方法的处理,然后增加一点新的逻辑.怎么保留原来类中对该方法的处理呢,当然是让代理类中有被代理类这个成员变量。代理模式包括静态代理和动态代理
先描述一下静态代理(程序员自己写代理类的源码):
public interface Tools {
publicvoid run();
publicvoid see();
}
public class Car implements Tools {
publicvoid run(){
System.out.println("car run.....");
}
publicvoid see(){
System.out.println("car see.....");
}
}
public class CarEnhance implements Tools {
private Tools tools;
public CarEnhance(Tools tools) {
super();
this.tools = tools;
}
@Override
public void run() {
System.out.println("before");
tools.run();
System.out.println("after");
}
@Override
public void see() {
System.out.println("before");
tools.see();
System.out.println("after");
}
}
public static void main(String[] args) {
Tools tools1=(Tools)new CarEnhance(new Car());
tools1.run();
}
之前我还以为代理类里面有被代理类这个成员变量,其实代理类里面的成员变量是被代理类实现的那个接口,静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类。这里面接口是固定的,而在动态代理中接口为innvocationHandler,
就可以增强run方法和see方法,但是我们发现一个问题:如果我有大量的方法增加相同的逻辑,那么很显然这种方式非常的麻烦,因为你要实现每一个方法,然后在那个方法的前后增加逻辑。而且如果对不同的类中的方法增加相同的逻辑,那么对多少个类进行增强,就要写多少个代理类,所以静态代理的方式并不适用。
下面是在JDK中动态代理实现的方法:
先上文字描述:
首先是固定的类代理,假设为Proxy,他的功能是返回一个Car的代理。当然对方法的增强的方式肯定要我们自己写。既然是动态生成代理类,肯定是代码在proxy中生成,我们给proxy一个字符串SRC,里面是代理类的代码字符串,我们要把他生成一个Java文件,这个时候我们需要的只是Java类的名字和接口无关,用IO就可以生成这个,然后要把他编译成class类,这个时候也只是需要文件的名字而已,而后要把他加载到内存,还是只需要Java的名字,加载到内存之后要给调用者返回一个代理对象,这个时候需要接口的名字,然后把对象返回给调用者即可
上面的代码写的太死了,下面一步一步的把让弄活
首先让接口能够动态传入
需要改的地方有:SRC字符串实现接口的时候名字要把他动态加上去
接口中的方法要能动态的找出来,这里定义了一个字符串methodStr,然后用反射技术把方法名都找出来,现在先固定在对每一个方法都做相同的处理,在加载内存的时候他还是沿用第一个版本的方法写的是死的接口的名字
现在要让代理类代理的方法怎么执行可以动态的执行,可以动态的指定对某一个方法进行处理,先定义一个接口InvocationHandler来处理方法,然后定义一个TimeHandler来实现接口InvocationHandler,,,h.invoke(this,md),其实这个方法是拿到外面执行去啦,要对方法进行什么样的处理呢,就是timeHandler的处理,代理类的构造方法参数变成了InvocationHandler(好吧,这好像也叫实现同一个接口,怎么我感觉这样的话就一次只能对一个方法进行代理了,也即是里面不再有movable t这个对象了)
具体代码实现:
public interface Tools {
public void run();
public void see();
}
public class Car {
public void run(){
System.out.println("car run.....");
}
public void see(){
System.out.println("car see.....");
}
}
对Car类中的所有的方法进行增强的方式为:
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
super();
this.target = target;
}
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread()
.getContextClassLoader(), target.getClass().getInterfaces(),
this);
}
@Override
public Object invoke(Object proxy, Methodmethod, Object[] args)
throws Throwable {
String name=method.getName();
System.out.println("****"+name);
System.out.println("-----before -----");
Object result = method.invoke(target, args);
System.out.println("-----after -----");
returnresult;
}
}
测试如下:
Tools tools1=new Car();
MyInvocationHandler ih=newMyInvocationHandler(tools1);//增强的都是tools接口中的方法
Tools tools2=(Tools)ih.getProxy();
tools2.run();
该种方法可以只写一次增强逻辑,很显然他用的是反射,不管是静态代理还是动态代理,把需要代理的方法抽取成一个接口,他还有一个优势,可以使用相同的逻辑增强不同的类,而按照我们第一种方式他就只能增强使用该增强逻辑增强那一个类。