通过ClassLoader调用外部jar包
生活随笔
收集整理的這篇文章主要介紹了
通过ClassLoader调用外部jar包
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
通過ClassLoader調用外部jar包
package?org.loon.framework.jar;
/**?*//**
?*?<p>Title:?LoonFramework</p>
?*?<p>Description:JarLoader,用于jar包的外部操作</p>
?*?<p>Copyright:?Copyright?(c)?2007</p>
?*?<p>Company:?LoonFramework</p>
?*?@author?chenpeng??
?*?@email:ceponline@yahoo.com.cn?
?*?@version?0.1
?*/
import?java.io.BufferedInputStream;
import?java.io.ByteArrayInputStream;
import?java.io.ByteArrayOutputStream;
import?java.io.File;
import?java.io.FileInputStream;
import?java.io.FileNotFoundException;
import?java.io.IOException;
import?java.io.InputStream;
import?java.lang.reflect.Method;
import?java.net.MalformedURLException;
import?java.net.URL;
import?java.util.ArrayList;
import?java.util.HashMap;
import?java.util.Hashtable;
import?java.util.jar.JarEntry;
import?java.util.jar.JarInputStream;
import?java.util.jar.Manifest;
public?class?JarLoader?extends?ClassLoader?...{
????//資源緩存
????public?static?Hashtable?resources?=?new?Hashtable();
?
????public?static?JarLoader?loader?=?new?JarLoader();
????public?static?Class?load(byte[]?resource)?throws?Exception?...{
????????//?主函數所在類全稱
????????String?mainClassName?=?"";
????????//class資源及實體緩存
????????ArrayList?classNames?=?new?ArrayList();
????????ArrayList?classBuffers?=?new?ArrayList();
????????//?存儲依賴類
????????HashMap?depends?=?new?HashMap();
????????//?將byte[]轉為JarInputStream
????????JarInputStream?jar?=?new?JarInputStream(new?ByteArrayInputStream(
????????????????resource));
????????Manifest?manifest?=?jar.getManifest();
????????//?當Main-Class被聲明時,獲得主函數所在類全稱
????????if?(manifest?!=?null)?...{
????????????mainClassName?=?manifest.getMainAttributes().getValue("Main-Class");
????????}
????????//?依次獲得對應JAR文件中封裝的各個被壓縮文件的JarEntry
????????JarEntry?entry;
????????while?((entry?=?jar.getNextJarEntry())?!=?null)?...{
????????????//?當找到的entry為class時
????????????if?(entry.getName().toLowerCase().endsWith(".class"))?...{
????????????????//?將類路徑轉變為類全稱
????????????????String?name?=?entry.getName().substring(0,
????????????????????????entry.getName().length()?-?".class".length()).replace(
????????????????????????'/',?'.');
????????????????//?加載該類
????????????????byte[]?data?=?getResourceData(jar);
????????????????//?緩存類名及數據
????????????????classNames.add(name);
????????????????classBuffers.add(data);
????????????}?else?...{
????????????????//?非class結尾但開頭字符為'/'時
????????????????if?(entry.getName().charAt(0)?==?'/')?...{
????????????????????resources.put(entry.getName(),?getResourceData(jar));
????????????????//?否則追加'/'后緩存????
????????????????}?else?...{
????????????????????resources.put("/"?+?entry.getName(),?getResourceData(jar));
????????????????}
????????????}
????????}
????????//當獲得的main-class名不為空時
????????while?(classNames.size()?>?0)?...{
????????????//獲得類路徑全長
????????????int?n?=?classNames.size();
????????????for?(int?i?=?classNames.size()?-?1;?i?>=?0;?i--)?...{
????????????????try?...{
????????????????????//查詢指定類
????????????????????loader.defineClass((String)?classNames.get(i),
????????????????????????????(byte[])?classBuffers.get(i),?0,
????????????????????????????((byte[])?classBuffers.get(i)).length);
????????????????????//獲得類名
????????????????????String?pkName?=?(String)?classNames.get(i);
????????????????????if?(pkName.lastIndexOf('.')?>=?0)?...{
????????????????????????pkName?=?pkName
????????????????????????????????.substring(0,?pkName.lastIndexOf('.'));
????????????????????????if?(loader.getPackage(pkName)?==?null)?...{
????????????????????????????loader.definePackage(pkName,?null,?null,?null,
????????????????????????????????????null,?null,?null,?null);
????????????????????????}
????????????????????}
????????????????????//查詢后刪除緩沖
????????????????????classNames.remove(i);
????????????????????classBuffers.remove(i);
????????????????}?catch?(NoClassDefFoundError?e)?...{
????????????????????depends.put((String)?classNames.get(i),?e.getMessage()
????????????????????????????.replaceAll("/",?"."));
????????????????}?catch?(UnsupportedClassVersionError?e)?...{
????????????????????//jre版本錯誤提示
????????????????????throw?new?UnsupportedClassVersionError(classNames.get(i)
????????????????????????????+?",?"?+?System.getProperty("java.vm.name")?+?"?"
????????????????????????????+?System.getProperty("java.vm.version")?+?")");
????????????????}
????????????}
????????????if?(n?==?classNames.size())?...{
????????????????for?(int?i?=?0;?i?<?classNames.size();?i++)?...{
????????????????????System.err.println("NoClassDefFoundError:"
????????????????????????????+?classNames.get(i));
????????????????????String?className?=?(String)?classNames.get(i);
????????????????????while?(depends.containsKey(className))?...{
????????????????????????className?=?(String)?depends.get(className);
????????????????????}
????????????????}
????????????????break;
????????????}
????????}
????????try?...{
????????????//加載
????????????Thread.currentThread().setContextClassLoader(loader);
????????????//?獲得指定類,查找其他類方式相仿
????????????return?Class.forName(mainClassName,?true,?loader);
????????}?catch?(ClassNotFoundException?e)?...{
????????????String?className?=?mainClassName;
????????????while?(depends.containsKey(className))?...{
????????????????className?=?(String)?depends.get(className);
????????????}
????????????throw?new?ClassNotFoundException(className);
????????}
????}
????/**?*//**
?????*?獲得指定路徑文件的byte[]形式
?????*?@param?name
?????*?@return
?????*/
????final?static?public?byte[]?getDataSource(String?name)?...{
????????FileInputStream?fileInput;
????????try?...{
????????????fileInput?=?new?FileInputStream(new?File(name));
????????}?catch?(FileNotFoundException?e)?...{
????????????fileInput?=?null;
????????}
????????BufferedInputStream?bufferedInput?=?new?BufferedInputStream(fileInput);
????????return?getDataSource(bufferedInput);
????}
????
????/**?*//**
?????*?獲得指定InputStream的byte[]形式
?????*?@param?name
?????*?@return
?????*/
????final?static?public?byte[]?getDataSource(InputStream?is)?...{
????????if?(is?==?null)?...{
????????????return?null;
????????}
????????ByteArrayOutputStream?byteArrayOutputStream?=?new?ByteArrayOutputStream();
????????byte[]?arrayByte?=?null;
????????try?...{
????????????byte[]?bytes?=?new?byte[8192];
????????????bytes?=?new?byte[is.available()];
????????????int?read;
????????????while?((read?=?is.read(bytes))?>=?0)?...{
????????????????byteArrayOutputStream.write(bytes,?0,?read);
????????????}
????????????arrayByte?=?byteArrayOutputStream.toByteArray();
????????}?catch?(IOException?e)?...{
????????????return?null;
????????}?finally?...{
????????????try?...{
????????????????if?(byteArrayOutputStream?!=?null)?...{
????????????????????byteArrayOutputStream.close();
????????????????????byteArrayOutputStream?=?null;
????????????????}
????????????????if?(is?!=?null)?...{
????????????????????is.close();
????????????????????is?=?null;
????????????????}
????????????}?catch?(IOException?e)?...{
????????????}
????????}
????????return?arrayByte;
????}
????/**?*//**
?????*?獲得指定JarInputStream的byte[]形式
?????*?@param?jar
?????*?@return
?????*?@throws?IOException
?????*/
?????final?static?private?byte[]?getResourceData(JarInputStream?jar)
????????????throws?IOException?...{
????????ByteArrayOutputStream?data?=?new?ByteArrayOutputStream();
????????byte[]?buffer?=?new?byte[8192];
????????int?size;
????????while?(jar.available()?>?0)?...{
????????????size?=?jar.read(buffer);
????????????if?(size?>?0)?...{
????????????????data.write(buffer,?0,?size);
????????????}
????????}
????????return?data.toByteArray();
????}
?????/**?*//**
??????*?重載的getResource,檢查是否重復包含
??????*/
????public?URL?getResource(String?name)?...{
????????if?(resources.containsKey("/"?+?name))?...{
????????????try?...{
????????????????return?new?URL("file:///"?+?name);
????????????}?catch?(MalformedURLException?e)?...{
????????????????e.printStackTrace();
????????????}
????????}
????????return?super.getResource(name);
????}
????/**?*//**
?????*?執行指定class類
?????*?@param?clz
?????*?@param?methodName
?????*?@param?args
?????*/
????public?static?void?callVoidMethod(Class?clz,?String?methodName,
????????????String[]?args)?...{
????????Class[]?arg?=?new?Class[1];
????????arg[0]?=?args.getClass();
????????try?...{
????????????Method?method?=?clz.getMethod(methodName,?arg);
????????????Object[]?inArg?=?new?Object[1];
????????????inArg[0]?=?args;
????????????method.invoke(clz,?inArg);
????????}?catch?(Exception?e)?...{
????????????System.err.println(e.getMessage());
????????}
????}
????
?????/**?*//**
??????*?重載的getResourceAsStream,檢查是否重復包含
??????*/
????public?InputStream?getResourceAsStream(String?name)?...{
????????if?(name.charAt(0)?==?'/')?...{
????????????name?=?name.substring(1);
????????}
????????if?(resources.containsKey("/"?+?name))?...{
????????????return?new?ByteArrayInputStream((byte[])?resources.get("/"?+?name));
????????}
????????return?super.getResourceAsStream(name);
????}
}
運行示例:
package?org.loon.framework.jar;
/**?*//**
?*?<p>
?*?Title:?LoonFramework
?*?</p>
?*?<p>
?*?Description:從外部啟動jar包
?*?</p>
?*?<p>
?*?Copyright:?Copyright?(c)?2007
?*?</p>
?*?<p>
?*?Company:?LoonFramework
?*?</p>
?*?
?*?@author?chenpeng
?*?@email:ceponline@yahoo.com.cn
?*?@version?0.1
?*/
public?class?JarTest?...{
????public?static?void?main(String[]?args)?...{
????????//將jar包轉為byte[]
????????byte[]?resource?=?JarLoader.getDataSource("D:/fps_test.jar");
????????try?...{
????????????//通過byte[]獲得主函數所在類
????????????Class?clz?=?JarLoader.load(resource);
????????????//調用main函數
????????????JarLoader.callVoidMethod(clz,?"main",?new?String[]?...{""});
????????}?catch?(Exception?e)?...{
????????????e.getStackTrace();
????????}
????}
}
這時即使指定jar包沒有被我們添加到lib中,程序依舊被順利啟動了。
但是有個缺點,在沒有優化的前提下,這種直接加載外部包的速度在jvm會有很大損耗。
我們可以看到,fps值降低到正常值的50%左右(此fps實例見我CSDN以前的文章),所以并不適合直接運用在需要復雜運算的jar中類調用上(當然,有興趣的話,可以在代碼中優化,我自己在項目中寫的另一個例子速度明顯比這個快)。但是對于運算量小的外部jar調用,還是很方便的。 posted on 2007-11-12 15:38 cping 閱讀(...) 評論(...) 編輯 收藏
我們大家都知道,每個運行中的線程都有一個成員contextClassLoader,用來在運行時動態地載入其它類。
系統默認的contextClassLoader是systemClassLoader,所以一般而言java程序在執行時可以使用JVM自帶的類、$JAVA_HOME/jre/lib/ext/中的類和$CLASSPATH/中的類,對于非默認的jar,一般只能手動在配置環境添加。
但事實上,我們可以通過Thread.currentThread().setContextClassLoader()更改當前線程的contextClassLoader行為,實現在程序內加載外部jar。
PS:
ClassLoader的工作原理是:
1) 線程需要用到某個類時,contextClassLoader將被請求來載入該類
2) contextClassLoader請求它的父ClassLoader來完成該載入請求
3) 如果父ClassLoader無法載入類,則contextClassLoader試圖自己來載入
package?org.loon.framework.jar;
/**?*//**
?*?<p>Title:?LoonFramework</p>
?*?<p>Description:JarLoader,用于jar包的外部操作</p>
?*?<p>Copyright:?Copyright?(c)?2007</p>
?*?<p>Company:?LoonFramework</p>
?*?@author?chenpeng??
?*?@email:ceponline@yahoo.com.cn?
?*?@version?0.1
?*/
import?java.io.BufferedInputStream;
import?java.io.ByteArrayInputStream;
import?java.io.ByteArrayOutputStream;
import?java.io.File;
import?java.io.FileInputStream;
import?java.io.FileNotFoundException;
import?java.io.IOException;
import?java.io.InputStream;
import?java.lang.reflect.Method;
import?java.net.MalformedURLException;
import?java.net.URL;
import?java.util.ArrayList;
import?java.util.HashMap;
import?java.util.Hashtable;
import?java.util.jar.JarEntry;
import?java.util.jar.JarInputStream;
import?java.util.jar.Manifest;
public?class?JarLoader?extends?ClassLoader?...{
????//資源緩存
????public?static?Hashtable?resources?=?new?Hashtable();
?
????public?static?JarLoader?loader?=?new?JarLoader();
????public?static?Class?load(byte[]?resource)?throws?Exception?...{
????????//?主函數所在類全稱
????????String?mainClassName?=?"";
????????//class資源及實體緩存
????????ArrayList?classNames?=?new?ArrayList();
????????ArrayList?classBuffers?=?new?ArrayList();
????????//?存儲依賴類
????????HashMap?depends?=?new?HashMap();
????????//?將byte[]轉為JarInputStream
????????JarInputStream?jar?=?new?JarInputStream(new?ByteArrayInputStream(
????????????????resource));
????????Manifest?manifest?=?jar.getManifest();
????????//?當Main-Class被聲明時,獲得主函數所在類全稱
????????if?(manifest?!=?null)?...{
????????????mainClassName?=?manifest.getMainAttributes().getValue("Main-Class");
????????}
????????//?依次獲得對應JAR文件中封裝的各個被壓縮文件的JarEntry
????????JarEntry?entry;
????????while?((entry?=?jar.getNextJarEntry())?!=?null)?...{
????????????//?當找到的entry為class時
????????????if?(entry.getName().toLowerCase().endsWith(".class"))?...{
????????????????//?將類路徑轉變為類全稱
????????????????String?name?=?entry.getName().substring(0,
????????????????????????entry.getName().length()?-?".class".length()).replace(
????????????????????????'/',?'.');
????????????????//?加載該類
????????????????byte[]?data?=?getResourceData(jar);
????????????????//?緩存類名及數據
????????????????classNames.add(name);
????????????????classBuffers.add(data);
????????????}?else?...{
????????????????//?非class結尾但開頭字符為'/'時
????????????????if?(entry.getName().charAt(0)?==?'/')?...{
????????????????????resources.put(entry.getName(),?getResourceData(jar));
????????????????//?否則追加'/'后緩存????
????????????????}?else?...{
????????????????????resources.put("/"?+?entry.getName(),?getResourceData(jar));
????????????????}
????????????}
????????}
????????//當獲得的main-class名不為空時
????????while?(classNames.size()?>?0)?...{
????????????//獲得類路徑全長
????????????int?n?=?classNames.size();
????????????for?(int?i?=?classNames.size()?-?1;?i?>=?0;?i--)?...{
????????????????try?...{
????????????????????//查詢指定類
????????????????????loader.defineClass((String)?classNames.get(i),
????????????????????????????(byte[])?classBuffers.get(i),?0,
????????????????????????????((byte[])?classBuffers.get(i)).length);
????????????????????//獲得類名
????????????????????String?pkName?=?(String)?classNames.get(i);
????????????????????if?(pkName.lastIndexOf('.')?>=?0)?...{
????????????????????????pkName?=?pkName
????????????????????????????????.substring(0,?pkName.lastIndexOf('.'));
????????????????????????if?(loader.getPackage(pkName)?==?null)?...{
????????????????????????????loader.definePackage(pkName,?null,?null,?null,
????????????????????????????????????null,?null,?null,?null);
????????????????????????}
????????????????????}
????????????????????//查詢后刪除緩沖
????????????????????classNames.remove(i);
????????????????????classBuffers.remove(i);
????????????????}?catch?(NoClassDefFoundError?e)?...{
????????????????????depends.put((String)?classNames.get(i),?e.getMessage()
????????????????????????????.replaceAll("/",?"."));
????????????????}?catch?(UnsupportedClassVersionError?e)?...{
????????????????????//jre版本錯誤提示
????????????????????throw?new?UnsupportedClassVersionError(classNames.get(i)
????????????????????????????+?",?"?+?System.getProperty("java.vm.name")?+?"?"
????????????????????????????+?System.getProperty("java.vm.version")?+?")");
????????????????}
????????????}
????????????if?(n?==?classNames.size())?...{
????????????????for?(int?i?=?0;?i?<?classNames.size();?i++)?...{
????????????????????System.err.println("NoClassDefFoundError:"
????????????????????????????+?classNames.get(i));
????????????????????String?className?=?(String)?classNames.get(i);
????????????????????while?(depends.containsKey(className))?...{
????????????????????????className?=?(String)?depends.get(className);
????????????????????}
????????????????}
????????????????break;
????????????}
????????}
????????try?...{
????????????//加載
????????????Thread.currentThread().setContextClassLoader(loader);
????????????//?獲得指定類,查找其他類方式相仿
????????????return?Class.forName(mainClassName,?true,?loader);
????????}?catch?(ClassNotFoundException?e)?...{
????????????String?className?=?mainClassName;
????????????while?(depends.containsKey(className))?...{
????????????????className?=?(String)?depends.get(className);
????????????}
????????????throw?new?ClassNotFoundException(className);
????????}
????}
????/**?*//**
?????*?獲得指定路徑文件的byte[]形式
?????*?@param?name
?????*?@return
?????*/
????final?static?public?byte[]?getDataSource(String?name)?...{
????????FileInputStream?fileInput;
????????try?...{
????????????fileInput?=?new?FileInputStream(new?File(name));
????????}?catch?(FileNotFoundException?e)?...{
????????????fileInput?=?null;
????????}
????????BufferedInputStream?bufferedInput?=?new?BufferedInputStream(fileInput);
????????return?getDataSource(bufferedInput);
????}
????
????/**?*//**
?????*?獲得指定InputStream的byte[]形式
?????*?@param?name
?????*?@return
?????*/
????final?static?public?byte[]?getDataSource(InputStream?is)?...{
????????if?(is?==?null)?...{
????????????return?null;
????????}
????????ByteArrayOutputStream?byteArrayOutputStream?=?new?ByteArrayOutputStream();
????????byte[]?arrayByte?=?null;
????????try?...{
????????????byte[]?bytes?=?new?byte[8192];
????????????bytes?=?new?byte[is.available()];
????????????int?read;
????????????while?((read?=?is.read(bytes))?>=?0)?...{
????????????????byteArrayOutputStream.write(bytes,?0,?read);
????????????}
????????????arrayByte?=?byteArrayOutputStream.toByteArray();
????????}?catch?(IOException?e)?...{
????????????return?null;
????????}?finally?...{
????????????try?...{
????????????????if?(byteArrayOutputStream?!=?null)?...{
????????????????????byteArrayOutputStream.close();
????????????????????byteArrayOutputStream?=?null;
????????????????}
????????????????if?(is?!=?null)?...{
????????????????????is.close();
????????????????????is?=?null;
????????????????}
????????????}?catch?(IOException?e)?...{
????????????}
????????}
????????return?arrayByte;
????}
????/**?*//**
?????*?獲得指定JarInputStream的byte[]形式
?????*?@param?jar
?????*?@return
?????*?@throws?IOException
?????*/
?????final?static?private?byte[]?getResourceData(JarInputStream?jar)
????????????throws?IOException?...{
????????ByteArrayOutputStream?data?=?new?ByteArrayOutputStream();
????????byte[]?buffer?=?new?byte[8192];
????????int?size;
????????while?(jar.available()?>?0)?...{
????????????size?=?jar.read(buffer);
????????????if?(size?>?0)?...{
????????????????data.write(buffer,?0,?size);
????????????}
????????}
????????return?data.toByteArray();
????}
?????/**?*//**
??????*?重載的getResource,檢查是否重復包含
??????*/
????public?URL?getResource(String?name)?...{
????????if?(resources.containsKey("/"?+?name))?...{
????????????try?...{
????????????????return?new?URL("file:///"?+?name);
????????????}?catch?(MalformedURLException?e)?...{
????????????????e.printStackTrace();
????????????}
????????}
????????return?super.getResource(name);
????}
????/**?*//**
?????*?執行指定class類
?????*?@param?clz
?????*?@param?methodName
?????*?@param?args
?????*/
????public?static?void?callVoidMethod(Class?clz,?String?methodName,
????????????String[]?args)?...{
????????Class[]?arg?=?new?Class[1];
????????arg[0]?=?args.getClass();
????????try?...{
????????????Method?method?=?clz.getMethod(methodName,?arg);
????????????Object[]?inArg?=?new?Object[1];
????????????inArg[0]?=?args;
????????????method.invoke(clz,?inArg);
????????}?catch?(Exception?e)?...{
????????????System.err.println(e.getMessage());
????????}
????}
????
?????/**?*//**
??????*?重載的getResourceAsStream,檢查是否重復包含
??????*/
????public?InputStream?getResourceAsStream(String?name)?...{
????????if?(name.charAt(0)?==?'/')?...{
????????????name?=?name.substring(1);
????????}
????????if?(resources.containsKey("/"?+?name))?...{
????????????return?new?ByteArrayInputStream((byte[])?resources.get("/"?+?name));
????????}
????????return?super.getResourceAsStream(name);
????}
}
運行示例:
package?org.loon.framework.jar;
/**?*//**
?*?<p>
?*?Title:?LoonFramework
?*?</p>
?*?<p>
?*?Description:從外部啟動jar包
?*?</p>
?*?<p>
?*?Copyright:?Copyright?(c)?2007
?*?</p>
?*?<p>
?*?Company:?LoonFramework
?*?</p>
?*?
?*?@author?chenpeng
?*?@email:ceponline@yahoo.com.cn
?*?@version?0.1
?*/
public?class?JarTest?...{
????public?static?void?main(String[]?args)?...{
????????//將jar包轉為byte[]
????????byte[]?resource?=?JarLoader.getDataSource("D:/fps_test.jar");
????????try?...{
????????????//通過byte[]獲得主函數所在類
????????????Class?clz?=?JarLoader.load(resource);
????????????//調用main函數
????????????JarLoader.callVoidMethod(clz,?"main",?new?String[]?...{""});
????????}?catch?(Exception?e)?...{
????????????e.getStackTrace();
????????}
????}
}
這時即使指定jar包沒有被我們添加到lib中,程序依舊被順利啟動了。
但是有個缺點,在沒有優化的前提下,這種直接加載外部包的速度在jvm會有很大損耗。
我們可以看到,fps值降低到正常值的50%左右(此fps實例見我CSDN以前的文章),所以并不適合直接運用在需要復雜運算的jar中類調用上(當然,有興趣的話,可以在代碼中優化,我自己在項目中寫的另一個例子速度明顯比這個快)。但是對于運算量小的外部jar調用,還是很方便的。 posted on 2007-11-12 15:38 cping 閱讀(...) 評論(...) 編輯 收藏
轉載于:https://www.cnblogs.com/cping1982/archive/2007/11/12/2258094.html
總結
以上是生活随笔為你收集整理的通过ClassLoader调用外部jar包的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 必然的宿命,绚然的《暗花》
- 下一篇: weekendplan