[tomcat7源码学习]经过ClassLoader测试动态加载Jar

ClassLoader测试动态加载Jar

1.写一个本身的ClassLoader,继承URLClassLoaderjava

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

相关文章
相关标签/搜索