您的位置:首页 > 其它

设计模式(代理模式--动态代理)

2015-08-02 13:20 441 查看
动态代理可以动态的实现所有接口,这是静态代理所不能胜任的。

前一章静态代理类固定实现了Imove接口,现在我们将该Imove接口类通过java的反射机制拿到所有接口,循环遍历其接口做实现如下面代码:

//代理对象处理类
package com.study.proxy;
import java.lang.reflect.Method;
public interface InvocationHandler {
public void invoke(Object o,Method m) throws Exception;
}


//日志处理对象
package com.study.proxy.real;
import java.lang.reflect.Method;
import com.study.proxy.InvocationHandler;
public class LogHandler implements InvocationHandler {
private Object obj;
public LogHandler(Object obj) {
super();
this.obj = obj;
}
@Override
public void invoke(Object o, Method m) throws Exception {
System.out.println("开始时间");
m.invoke(obj);
System.out.println("结束时间");
}
}


//代理对象实现该接口
package com.study.proxy;
public interface Imove {
public void move();
}


//代理对象
package com.study.proxy;
public class Tank implements Imove{
@Override
public void move() {
System.out.println("坦克在移动.....");
}
}


//总代理(代理类的生成)
package com.study.proxy.real;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
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;
import com.study.proxy.Imove;
import com.study.proxy.InvocationHandler;
import com.study.proxy.Tank;

public class Proxy {

//第一个参数就是从外面传入的接口类,第二个参数就是代理对象处理
public static Object  newProxyInstance(Class inface,InvocationHandler h) throws Exception {
String rt="\r\n";
Method[] method=inface.getMethods();
String methodStr=""
//通过java反射机制将接口对象中的所有方法拿到做循环实现
for(Method m:method){
methodStr=methodStr+
"   public void "+m.getName()+"() {"+rt+
"     try{"+rt+
"        Method md="+inface.getName()+".class.getMethod(\""+m.getName()+"\");"+rt+
"        h.invoke(this,md);"+rt+
"     }catch(Exception ex){" +rt+
"     }"+rt+
"   }"+rt;
System.out.println(m.getName());
}
//通过字符串拼接动态生成的代理类字符串
String str="package com.study.proxy.real;" +rt+
"import com.study.proxy.Imove;"+rt+
"import java.lang.reflect.Method;"+rt+
"import com.study.proxy.InvocationHandler;"+rt+
"public class TankMoveProxy implements " +inface.getName()+ " {"+rt+
"    private InvocationHandler h;"+rt+
"    public TankMoveProxy(InvocationHandler hander) {"+rt+
"      super();"+rt+
"      this.h = hander;"+rt+
"     }"+rt+methodStr+
"}";

String fileName = System.getProperty("user.dir") + "/src/com/study/proxy/real/TankMoveProxy.java";
//将动态生成代理类java代码写入指定的文件中
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(str);
fw.flush();
fw.close();
//编译生成的java类文件生成对应的class文件
JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager sjf = jc.getStandardFileManager(null, null, null);
Iterable iter = sjf.getJavaFileObjects(fileName);
CompilationTask ct = jc.getTask(null, sjf, null, null, null, iter);
ct.call();
sjf.close();
//加载生成的class文件到内存中
URL[] urls = new URL[] { new URL("file:/" + System.getProperty("user.dir") + "/src") };
URLClassLoader ul = new URLClassLoader(urls);
class c = ul.loadClass("com.study.proxy.real.TankMoveProxy");
//将代理对象的委托处理类传入代理类中并生成代理类实例对象返回
Constructor cons = c.getConstructor(InvocationHandler.class);
Object o =  cons.newInstance(h);
return o;
}
}
</pre><pre name="code" class="java">//客户端使用代理总类
package com.study.proxy;
import java.io.IOException;
import java.util.Map;
import com.study.proxy.real.LogHandler;
import com.study.proxy.real.Proxy;

public class Client {
/**
* @param args
*/
public static void main(String[] args) {
Tank tank = new Tank();
try {
InvocationHandler handler=new LogHandler(tank);
Imove proxyTank=(Imove)Proxy.newProxyInstance(Imove.class,handler);
proxyTank.move();
} catch (Exception e) {
e.printStackTrace();
}
}
}


执行以上代码输出:

开始时间

坦克在移动.....

结束时间

根据输出的内容,明显的动态的在坦克移动功能前后加上了其他业务处理逻辑。

其实以上Proxy类得功能就是实现动态生成代理类,这个类可以说是所有代理类的总代理。newProxyInstance方法中传入代理类实现的接口以及代理对象委托实现,通过java的反射机制拿到了实现接口的所有方法,循环遍历所有方法即可让代理对象实现接口的所有方法。这时代理类的java代码通过字符串拼接后写入到java类文件中。通过JDK自带的编译器JavaCompiler编译JAVA文件生成对应的class文件。通过类加载器加载到类存中生成对象返回给客户端。这样代理的功能就实现了,它的好处是能动态的实现接口中的所有方法。将主体核心的业务逻辑与公用的业务逻辑剥离开,比如需要计算代理对象运行了多长时间,在不改变核心业务代码的前提下就能在方法前后加上你的计算时间的代码。这段代码的功能与JDK1.6中的的代理实现机制一样,只是这里比JDK1.6中的简单一些。在spring中AOP面向切面编程也是代理的一种应用,这里的机制跟spring的机制也很像。spring生成class文件有两种生成方式
一种是JDK1.6中的编译,还有一种是cglib。cglib是不生成class文件,直接读入到类存中去。而jdk1.6的JavaCompiler是生成class编译文件,然后再通过classload加载进Jvm。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: