在class文件格式与执行引擎这部分中,用的程序能直接影响的内容并不太多,class文件以何种格式存储,类型何时加载,如何连接,以及虚拟机如何执行字节码指令都是由虚拟机直接控制的行为,用户程序无法对其进行改变。能通过程序进行操作的,主要是字节码生成与类加载器这两部分功能。
一。Tomcat:正统的类加载架构
主流的java web服务器,如Tomcat,Jetty,WebLogic,WebSphere等的服务器,都实现了自己定义的类加载器,因为一个健全的Web服务器,要解决以下几个问题:
1.部署在同一个服务器上的两个Web应用程序所使用的java类库可以实现相互隔离
2.部署在同一个服务器上的两个Web应用程序所使用的java类库可以相互共享。
3.服务器需要尽可能地保证 自身的安全不受部署Web应用程序影响 。
4.支持JSP应用的Web服务器,大多数都需要支持HotSwap功能。
在Tomcat目录结构中,有3组目录(“/common/*”,"/server/*"和“/shared/*”)可以存放在java类库,另外还可以加上Web应用程序自身的目录“WEB-INF/*”,一共4组,把java类库位置在这些目录中含义分别如下
/common/ | 类可被Tomcat和所有Web应用程序共同使用 |
/server/ | 类可被Tomcat使用,对所有的Web应用程序都不可见 |
/share/ | 类库可被所有的Web应用程序共同使用,但对Tomcat自己不可见 |
/WebApp/WEB-INF | 仅仅可以被此Web应用程序使用,对Tomcat和其他Web应用程序都不可见 |
从以上图中看得出来,Tomcat使用的是双亲委派模型来实现的
二。OSGI灵活的类加载器架构
所以上图中的类加载器没有指明具体的加载器实现,只是一个体现了加载器之间关系的概念模型,并且只是体现了OSGi中最简单的加载器委派关系。一般来说,在OSGi中,加载一个类可能发生的查找行为和委派关系会比上图中显示的复杂,类加载时的查找规则如下:
1)以java.*开头的类,委派给父类加载器加载
2)否则,委派列表名单内的类,委派给父类加载器加载
3)否则,Import列表中的类,委派给Export这个类的Bundle的类加载器加载
4)否则,查找当前Bundle的ClassPath,使用自己的类加载器加载
5)否则,查找是否在自己的Fragment Bundle中,如果是,则委派给Fragment bundle的类加载器加载
6)否则,查找Dynamic Import列表的Bundle,委派给对应Bundle的类加载器加载
7)否则,查找失败
从之前的图可以看出,在OSGi里面,加载器的关系不再是双亲委派模型的树形架构,而是已经进一步发展成了一种更复杂的、运行时才能确定的网状结构。
三。字节码生成技术与动态代理的实现
字节码生成并不是什么高深的技术,看到这个标题也先不必去想诸如Javassist,CGLib,ASM之类的字节码类,因为JDK里面的javac命令就是字节码生成技术“老祖宗”,并且javac也是一个由java程序写成的程序,要深入了解字节码生成,阅读javac的源码是个很好的途径,不过javac对于我们这个例子来说太过庞大了。
动态代理中所谓的动态,是针对使用Java代码实际编写了代理类的静态代理而言,它的优势不在于省去了代理行为,当代理类与原始类脱离直接联系后,就可以很灵活重用不同的应用场景之中。 以下实现最简单的动态代理的用法
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class TestPoxy {
interface IHello{
void sayHello();
}
static class Hello implements IHello{
public void sayHello(){
System.out.println("hello world");
}
}
static class DynamicProxy implements InvocationHandler{
Object orignalObj;
Object bind(Object originalObj){
this.orignalObj= originalObj;
return Proxy.newProxyInstance(originalObj.getClass().getClassLoader(),originalObj.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy, Method method,Object[] args)throws Throwable{
System.out.println("welcome");
return method.invoke(orignalObj,args);
}
}
public static void main(String[] args){
IHello hello = (IHello) new DynamicProxy().bind(new Hello());
hello.sayHello();
}
}
三。Retrotranslator:跨越JDK版本
学习http://retrotranslator.sourceforge.net/这篇文章