很多時候人們會使用一些自定義的ClassLoader
而不是使用系統的Class Loader
大多數時候人們這樣做的原因是
他們在編譯時無法預知運行時會需要那些Class
特別是在那些appserver中
比如tomcat
Avalon
phonix
Jboss中
或是程序提供一些plug
in的功能
用戶可以在程序編譯好之後再添加自己的功能
比如ant
jxta
shell等
定制一個ClassLoader很簡單
一般只需要理解很少的幾個方法就可以完成
一個最簡單的自定義的ClassLoader從ClassLoader類繼承而來
這裡我們要做一個可以在運行時指定路徑
加載這個路徑下的class的ClassLoader
通常我們使用ClassLoader
loadClass(String):Class方法
通過給出一個類名
就會得到一個相應的Class實例
因此只要小小的改動這個方法
就可以實現我們的願望了
源碼
protected synchronized Class loadClass(String name
boolean resolve) throws ClassNotFoundException { // First
check if the class has already been loaded Class c = findLoadedClass(name); if (c == null) { try { if (parent != null) { c = parent
loadClass(name
false); }else{ c = findBootstrapClass
(name); } }catch(ClassNotFoundException e){ // If still not found
then call findClass in order // to find the class
c = findClass(name); } } if (resolve) { resolveClass(c); } return c;}
Source from ClassLoader
java
First
check JavaAPI doc
上面指出了缺省的loadClass方法所做的幾個步驟
調用findLoadedClass(String):Class 檢查一下這個class是否已經被加載過了
由於JVM 規范規定ClassLoader可以cache它所加載的Class
因此如果一個class已經被加載過的話
直接從cache中獲取即可
調用它的parent 的loadClass()方法
如果parent為空
這使用JVM內部的class loader(即著名的bootstrap classloader)
如果上面兩步都沒有找到
調用findClass(String)方法來查找並加載這個class
後面還有一句話
在Java
版本以後
鼓勵用戶通過繼承findClass(String)方法實現自己的class loader而不是繼承loadClass(String)方法
既然如此
那麼我們就先這麼做
)
public class AnotherClassLoader extends ClassLoader { private String baseDir;private static final Logger LOG = Logger
getLogger(AnotherClassLoader
class); public AnotherClassLoader (ClassLoader parent
String baseDir) { super(parent); this
baseDir = baseDir; } protected Class findClass(String name) throws ClassNotFoundException { LOG
debug(
findClass
+ name); byte[] bytes = loadClassBytes(name); Class theClass = defineClass(name
bytes
bytes
length);//A if (theClass == null) throw new ClassFormatError(); return theClass; } private byte[] loadClassBytes(String className) throws ClassNotFoundException { try { String classFile = getClassFile(className); FileInputStream fis = new FileInputStream(classFile); FileChannel fileC = fis
getChannel(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); WritableByteChannel outC = Channels
newChannel(baos); ByteBuffer buffer = ByteBuffer
allocateDirect(
); while (true) { int i = fileC
read(buffer); if (i ==
|| i ==
) { break; } buffer
flip(); outC
write(buffer); buffer
clear(); } fis
close(); return baos
toByteArray(); } catch (IOException fnfe) { throw new ClassNotFoundException(className); } } private String getClassFile(String name) { StringBuffer sb = new StringBuffer(baseDir); name = name
replace(
File
separatorChar) +
class
; sb
append(File
separator + name); return sb
toString(); }}
[i]Ps:這裡使用了一些JDK
的nio的代碼
)[/i]
很簡單的代碼
關鍵的地方就在A處
我們使用了defineClass方法
目的在於把從class文件中得到的二進制數組轉換為相應的Class實例
defineClass是一個native的方法
它替我們識別class文件格式
分析讀取相應的數據結構
並生成一個class實例
還沒完呢
我們只是找到了發布在某個目錄下的class
還有資源呢
我們有時會用Class
getResource():URL來獲取相應的資源文件
如果僅僅使用上面的ClassLoader是找不到這個資源的
相應的返回值為null
同樣我們看一下原來的ClassLoader內部的結構
public
URL getResource(String name) { name = resolveName(name); ClassLoader cl = getClassLoader
();//這裡 if (cl==null) { // A system class
return ClassLoader
getSystemResource(name); } return cl
getResource(name);}
原來是使用加載這個class的那個classLoader獲取得資源
public URL getResource(String name) { URL url; if (parent != null) { url = parent
getResource(name); } else { url = getBootstrapResource(name); } if (url == null) { url = findResource(name);//這裡 } return url;}
這樣看來只要繼承findResource(String)方法就可以了
修改以下我們的代碼
//新增的一個findResource方法protected URL findResource(String name) { LOG
debug(
findResource
+ name); try { URL url = super
findResource(name); if (url != null) return url; url = new URL(
file:///
+ converName(name)); //簡化處理
所有資源從文件系統中獲取 return url; } catch (MalformedURLException mue) { LOG
error(
findResource
mue); return null; }}private String converName(String name) { StringBuffer sb = new StringBuffer(baseDir); name = name
replace(
File
separatorChar); sb
append(File
separator + name); return sb
toString();}
好了
到這裡一個簡單的自定義的ClassLoader就做好了
你可以添加其他的調料(比如安全檢查
修改class文件等)
以滿足你自己的口味
)
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19625.html