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
应该是预留给开发人员来扩展,用这个应该能够作一些其它什么事?