1. 程式人生 > >Java動態編譯和動態載入詳解

Java動態編譯和動態載入詳解

一.動態編譯

在某些情況下,我們需要動態生成java程式碼,通過動態編譯,然後執行程式碼。JAVA API提供了相應的工具(JavaCompiler)來實現動態編譯。

//獲取JavaCompiler JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

//獲取java檔案管理類 StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);

//獲取java檔案物件迭代器 Iterable<? extends JavaFileObject> it = manager.getJavaFileObjects(files);

//設定編譯引數 ArrayList<String> ops = new ArrayList<String>(); ops.add("-Xlint:unchecked");

//可以指定原始檔或目標檔案的JDK版本 ops.add("-source")/ops.add("-target");; ops.add("1.5");

//獲取編譯任務:第一個null,用於輸出錯誤的流,預設是System.err;第二個null,diagnosticListener: 編譯器的預設行為 ;第三個null,classes,參與編譯的class,為null時表示全部

//JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, ops, null, it);

//執行編譯任務 task.call();

 

動態編譯幾個關鍵類

類名

作用

建立方式

JavaCompiler

動態編譯的入口,也是基礎類

ToolProvider.getSystemJavaCompiler()

StandardJavaFileManager

java檔案管理類

compiler.getStandardFileManager

Iterable

檔案物件迭代器

manager.getJavaFileObjects(files)

ArrayList<String> 

編譯引數

new ArrayList<String>()

 

踩坑記

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 這句程式碼在IDEA中執行正常,然後打成jar包在桌面雙擊執行時得到的是null

問題解決:

檢視ToolProvider原始碼可知,是因為找不到tools.jar---》將tools.jar複製到jre/lib下

 

二.動態載入

JAVA中的類載入:雙親委派模式

URL  url = new URL("file:" + CLASS_PATH);

ClassLoader  classLoader = new URLClassLoader(new URL[]{url});

Class<?> cls = classLoader.loadClass(name);

Method method = cls.getDeclaredMethod(String methodName)

Object obj = cls.newInstance();

Object result = method.invoke(Object obj, Object[] params);

 

class.forName()和classLoader區別:

 //Class.forName(String className)  這是1.8的原始碼

 public static Class<?> forName(String className) throws ClassNotFoundException {

        Class<?> caller = Reflection.getCallerClass();

        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);    

}      

//注意第二個引數,是指Class被loading後是不是必須被初始化。 不初始化就是不執行static的程式碼即靜態程式碼 class.forName()前者除了將類的.class檔案載入到jvm中之外,還會對類進行解釋,執行類中的static塊。

而classLoader只幹一件事情,就是將.class檔案載入到jvm中。

 

擴充套件:TOMCAT中的類載入架構

 

1、JAVA_HOME:設定為JDK的安裝目錄,如D:\java\jdk1.8。一些依賴JAVA的軟體通過該環境變數來獲得JDK的安裝目錄,如大家都知道的Eclipse、Tomcat等。

2、PATH:在已有值最後加上 ;%JAVA_HOME%\bin ,其中;是分隔符,用於分開每個目錄,其中%JAVA_HOME%則是引用上面的JAVA_HOME環境變數的值,可以直接用JDK的安裝目錄代替,下面的CLASSPATH類似。執行路徑(也就是PATH環境變數的值)是隻作業系統搜尋本地可執行檔案的目錄列表,在shell中執行命令時,它會在執行路徑中查詢所對應的程式。所以在PATH中加入了%JAVA_HOME%\bin目錄後,在shell中就可以執行javac或者java命令。

3、CLASSPATH:設定值為.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; 注意其中的標點符號,其中第一個點“.”表示當前目錄,而分號“;”則是分隔符。 這個CLASSPATH為JVM載入類的目錄,比如HelloWorld.java中有import其他類,用javac編譯時它會在CLASSPATH中去找你所import的類,如果找不到則出現編譯錯誤。 另外在使用java時使用-classpath 引數可以指定要載入類的目錄,比如命令列執行:C:/UsersJakey>java -classpath D:\temp HelloWorld  ,這樣就可以當命令列在C盤時執行D盤目錄中的JAVA類。