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

ClassLoader测试动态加载Jar

1.写一个自己的***ClassLoader***,继承URLClassLoader

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源码

2.编写测试类,里面没有直接引入其它package

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

可以看出已经成功执行

###总结###

1.运用这种方法,有时候我们可以动态的加入一些Jar,如:动态添加一些插件什么的。但这样效率如何还有待验证。

2.也可以直接像tomcat一样运用,对需要使用的Jar,不直接通过classpath引入,而用这种方式。tomcat7中的StandardClassLoader,是标记为@Deprecated的,而且里面也没有添加其它什么东西,和URLClassLoader一样

###补充###

通过进一步跟踪,发现URLClassLoader继承的ClassLoader,里面有很多关于加载的,目前看了一下,直接返回Class的有

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

转载于:https://my.oschina.net/remind2010/blog/180184

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值