1.寫一個本身的ClassLoader,繼承URLClassLoader
java
package com.tomcat7.test; import java.net.URL; import java.net.URLClassLoader; public class MyClassLoader extends URLClassLoader{ public MyClassLoader(URL[] urls) { super(urls); } public Class<?> findClass(final String name) throws ClassNotFoundException { return super.findClass(name); } }
這裏說下爲何要繼承,而不直接使用URLClassLoader
,是由於findClass
是protected
的,詳情可查看URLClassLoader
源碼apache
2.編寫測試類,裏面沒有直接引入其它packagetomcat
package com.tomcat7.test; import java.io.File; import java.lang.reflect.Method; import java.net.URL; public class ClassLoader { public static final String JAR_PATH = "E:\\maven\\repository\\commons-lang\\commons-lang\\2.6\\commons-lang-2.6.jar"; public static void main(String[] args) { try { URL[] urls = { (new File(JAR_PATH).toURI().toURL()) }; MyClassLoader loader = new MyClassLoader(urls); Class c = loader.findClass("org.apache.commons.lang.StringUtils"); Method method = c.getMethod("startsWith", String.class,String.class); Object ret = method.invoke(c, "abcd","ad"); System.out.println("ret:" + ret); } catch (Exception e) { e.printStackTrace(); } } }
3.運行測試類,輸出:網絡
ret:false
能夠看出已經成功執行maven
###總結###post
1.運用這種方法,有時候咱們能夠動態的加入一些Jar,如:動態添加一些插件什麼的。但這樣效率如何還有待驗證。測試
2.也能夠直接像tomcat同樣運用,對須要使用的Jar,不直接經過classpath引入,而用這種方式。tomcat7中的StandardClassLoader
,是標記爲@Deprecated
的,並且裏面也沒有添加其它什麼東西,和URLClassLoader
同樣this
###補充###url
經過進一步跟蹤,發現URLClassLoader
繼承的ClassLoader
,裏面有不少關於加載的,目前看了一下,直接返回Class
的有spa
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } } protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); } protected final Class<?> defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) throws ClassFormatError { protectionDomain = preDefineClass(name, protectionDomain); Class c = null; String source = defineClassSourceLocation(protectionDomain); try { c = defineClass1(name, b, off, len, protectionDomain, source); } catch (ClassFormatError cfe) { c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, source); } postDefineClass(c, protectionDomain); return c; }
findClass
沒有直接在ClssLoader
中實現,在子類實現,應該是預留讓開發人員能夠定製,像這裏的URLClassLoader
裏面就本身實現了。在調用loadClass
也有可能調用到findClass
。
問題:
1.這三個有什麼區別?看了一下API說defineClass
能夠以符合規範的Class
字節碼生成實例,如API中所說的
網絡類加載器子類必須定義方法 findClass 和 loadClassData,以實現從網絡加載類。下載組成該類的字節後,它應該使用方法 defineClass 來建立類實例。示例實現以下:
class NetworkClassLoader extends ClassLoader { String host; int port; public Class findClass(String name) { byte[] b = loadClassData(name); return defineClass(name, b, 0, b.length); } private byte[] loadClassData(String name) { // load the class data from the connection . . . } }
貌似能夠用來實現遠程調用。。。。
2.loadClass
好像功能最全一點,加載的優先級?對於上面的測試方法,應該能夠直接調用loadClass
。而不用再去本身寫一個MyClassLoader
重寫findClass
3.findClass
應該是預留給開發人員來擴展,用這個應該能夠作一些其它什麼事?