天天看點

JVM類加載及執行子系統

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上部署的版本。