分类:
2008-10-29 11:28:52
如果我们把一个JSP文件发布到Tomcat里边,JSP是可以动态改变得,也就是说随着这个JSP文件的改变,通过浏览器访问,可以获得不同的结果。然而有没有想过能够让java代码像jsp那样动态的改变?
实际上通过java的反射机制和内建的代理模式,完全可以做到这一点。下面就一步一步的说一下这是如何实现的。
1,准备知识
代理模式代理模式是一种对象的结构模式,简单的说就是给某个对象提供一个代理对象,并通过代理对象来访问真正的对象。
按照《java与模式》里边说说的,proxy其实有很多种用法:Remote proxy,Vitual Proxy,Copy-on-Write Proxy,Cache Proxy,Firewall proxy,Synchronization Proxy,Smart Reference Proxy等等。总体来说,都起到一个网络中代理的作用,只不过在代理中添加一些代码实现不同的功能。
代理模式的要点就是不直接访问要访问的对象,而是通过代理对象,因此就可以在调用实际对象前或调用后利用消息传递做一些额外的工作。
反射机制与动态编译java的反射机制是java被视为动态语言的重要特性,主要是通过java.lang.reflect包中提供的工具对于给定名称的class,filed,method进行访问。这种动态性给程序提供了很多的灵活性,本文要介绍的功能就得益于java的这一机制。
动态编译算是java反射的加强补充,在j2se 1.6以前的版本里边是通过tools.jar中的com.sun.tools.javac包来提供的,在当前已经发布的j2se1.6 beta2中已经将动态编译作为j2se的一部分了。
要让java代码能够像jsp那样动态的使用,需要探测到java文件的改变,并动态编译成class文件,再用ClassLoader将编译好的class载入,因此这一部分是不可或缺的。
的内建代理j2se在1.3以后提供了Proxy、InvocationHandler来支持代理模式。
对于java内建的代理来说,就是client不直接访问对象,而是通过Proxy对象来访问,而在访问实际对象前后我们可以自己定义一些其他的操作。
具体来讲,client访问的对象通过Proxy.newProxyInstance ()给出,client要访问的实际的类可以通过Proxy.getProxyClass获得,而实际的调用将访问到我们实现的 InvocationHandler对象的invoke()方法中来。在invoke()方法中我们可以为实际的调用添加额外的代码以满足不同的需要。
在我后边讲到的具体实现中就可以看到,我们正是在实现InvocationHandler的MyInvocationHandler的invoke()方法中来判断java文件的改变,对于改变动态的编译和装载和调用来达到我们预期的目标的,java内建的代理模式可谓居功至尾。
2,基本服务
为了演示像jsp一样的java的效果,让我们来定义的一种服务。
public interface Postman { void deliverMessage(String msg);}具体的实现中,候选的有两种方案:
第一种是将输出字符串到控制台:
public class PostmanImpl implements Postman { private PrintStream output; public PostmanImpl() { output = System.out; } public void deliverMessage(String msg) { output.println("[Postman] " + msg); |
第二种是输出字符串到文本:
[1]