[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應該是預留給開發人員來擴展,用這個應該能夠作一些其它什麼事?

相關文章
相關標籤/搜索