JVM类加载及执行子系统

时间:2022-12-25 14:28:23
JVM类加载及执行子系统总结

一,概述

    在Class文件格式和执行引擎这部分中,用户的程序能直接影响的内容并不多,Class文件以何种方式存储,类型
如何加载,如何连接,以及JVM如何执行字节码执行等都是由JVM直接控制的,用户程序无法对其进行改变。能通过程序
进行操作的,主要是字节码生成和类加载器这2部分内容。但仅仅在如何处理这两点上,就已经出现了许多值得借鉴的
新思路,这些新思路后来成为了许多常用功能和程序实现的基础。

二,案例分析

1,Tomcat:正统的类加载器架构
    主流的Java Web服务器,都实现了自己的类加载器,因为一个功能健全的Web服务器,要解决一下几个问题:
    * 部署在同一个服务器上的2个Web应用程序所使用的Java类库可以实现相互隔离,这是最基本的需求。
    * 部署在同一个服务器上的2个Wen应用程序所使用的Java类库可以相互共享。这个需求也很常见。
    * 服务器需要尽可能的保证自身的安全不受部署的Web应用程序的影响。
    * 支持JSP的Web服务器,一般都支持HotSwap功能。JSP文件最终要编译成Class文件才能执行,但是JSP文件由于其
纯文本存储的特性,运行时修改的概率大。因此一般的Web服务器都支持JSP生成类的热替换。当然,也有特殊情况,例
如运行在生成环境的WebLogic服务器默认就不会处理JSP文件的热替换。
    由于这些问题的存在,在部署Web应用时,单独的一个ClassPath就无法满足需求了,所以一般的Web服务器都会提供
多个ClassPath路径供用户存放第三方类库,这些类库一般都是以lib或者classes命名。被放置在不同路径中的类库,具
备不同的访问范围和服务对象,通常每一个目录都会有一个相应的自定义类加载器去加载放置在里面的Java类库。下面
我们看看tomcat是如何规划用户的类库的结构和类加载器的。


2,OSGI:灵活的类加载器架构

3,字节码生成技术与动态代理的实现
说到字节码生成技术,我们不得不提以下javac命令,javac命令,就是编译java源代码文件,生成字节码文件。其他的诸如
Javassist、CGLib、ASM这些字节码类库,都是生成字节码的技术。使用字节码技术的例子有很多,比如Web服务器中的JSP
编译器,编译时植入的AOP框架,还有很常用的动态代理技术,甚至在使用反射的时候虚拟机都有可能会在运行时生成字节码
来提高执行速度。我们通过相对简单的动态代理技术来看看字节码生成技术是如何影响程序运行的。

首先我们定义一个接口DynamicProxyTest_Interface,及其实现类DynamicProxyTest_Implements


package com.yangcq.jvm;
public interface DynamicProxyTest_Interface {
public void printHello();
}

package com.yangcq.jvm;
public class DynamicProxyTest_Implements implements DynamicProxyTest_Interface{
@Override
public void printHello() {
System.out.println("奥运会");
}
}

接下来,是重点,我们写一个动态代理类,这个类实现了InvocationHandler接口


package com.yangcq.jvm;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxyTest_Proxy implements InvocationHandler{

Object origianlClass;
Object bind(Object origianlClass){
this.origianlClass = origianlClass;
return Proxy.newProxyInstance(origianlClass.getClass().getClassLoader(), origianlClass.getClass().getInterfaces(), this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("北京");
return method.invoke(origianlClass, args);
}
}

OK ,接下来我们进行测试

package com.yangcq.jvm;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author yangcq
* @description 动态代理
* 1,动态代理可以在原始类和接口还未知的情况下,就确定代理类的代理行为。
* 当代理类和原始类脱离直接联系后,就可以很灵活的重用于不同的应用场景之中。
*
*/
public class DynamicProxyTest {
final static Log log = LogFactory.getLog(DynamicProxyTest.class);
public static void main(String[] args) {
DynamicProxyTest_Interface dynamicProxy = (DynamicProxyTest_Interface) new DynamicProxyTest_Proxy()
.bind(new DynamicProxyTest_Implements());
dynamicProxy.printHello();
}
}
动态代理的强大之处在于,动态代理可以在原始类和接口还未知的情况下,就确定代理类的代理行为。当代理类和原始类脱离直接联系后,
就可以很灵活的重用于不同的应用场景之中。大家可以思考一下,字节码生成技术的应用还有哪些,以及实现原理?
上面的代码最终生成字节码,调用的是sun.misc.ProxyGenerator.generateProxyClass()方法来完成生成字节码的动作的。这个方法
在运行时,会生成一个描述代理类的字节码byte[]数组。

4,Retrotranslator:跨越JDK版本
Retrotranslator是一个逆向移植工具,它可以把用JDK5编写的程序,放到JDK4中去部署使用。其实本质原理,就是对生成的字节码进行
处理,把JDK5编译出来的Class文件,转变成可以在JDK4上部署的版本。