如何改變類載入的雙親委派模式
阿新 • • 發佈:2018-12-13
package com.stand.job.common.classload; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import com.stand.job.common.utils.ArrayUtils; /** * * @author chichaofan * * 如果delegateLoad 為false載入順序如下 * * bootstrapsclassload -> extclassload -> 自定義各種類載入器 -> systemclassload * * 如果delegateLoad 為true為預設類載入器載入順序如下 * * bootstrapsclassload -> extclassload ->systemclassload -> 自定義各種類載入器 */ public class StandJobClassLoader extends URLClassLoader { // 是否遵守雙親模式,預設雙親 private boolean delegateLoad = true; private ClassLoader javaseClassLoader; StandJobClassLoader(boolean delegateLoad) { super(new URL[] {}); this.delegateLoad = delegateLoad; setJavaseClassLoader(); } StandJobClassLoader(ClassLoader parent, boolean delegateLoad) { super(new URL[] {}, parent); this.delegateLoad = delegateLoad; setJavaseClassLoader(); } // 拷貝tomcat程式碼 private void setJavaseClassLoader() { ClassLoader j = String.class.getClassLoader(); if (j == null) { j = getSystemClassLoader(); while (j.getParent() != null) { j = j.getParent(); } } this.javaseClassLoader = j; } public void addJars(File[] files) { if (ArrayUtils.isEmpty(files)) { return; } for (File file : files) { addJar(file); } } public void addJar(File file) { if (file != null && file.isFile() && file.getName().toLowerCase().endsWith(".jar")) { try { addURL(file.toURI().toURL()); } catch (MalformedURLException e) { e.printStackTrace(); } } } protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // 如果遵守雙親,呼叫原來 if (delegateLoad) { return super.loadClass(name, resolve); } Class<?> clazz = null; synchronized (getClassLoadingLock(name)) { /** * 判斷是否已經載入 */ try { clazz = findLoadedClass(name); if (clazz != null) { if (resolve) { resolveClass(clazz); } return clazz; } } catch (Throwable e) { } /** * 先有bootstrapsclassload和 extclassload載入 */ try { clazz = javaseClassLoader.loadClass(name); if (clazz != null) { if (resolve) { resolveClass(clazz); } return clazz; } } catch (Throwable e) { } /** * 再是最外層自定義classlaod載入 */ try { clazz = super.findClass(name); if (clazz != null) { if (resolve) { resolveClass(clazz); } return clazz; } } catch (Throwable e) { } /** * 最外層載入不了,呼叫預設後續的載入器繼續載入 */ try { clazz = super.loadClass(name, resolve); if (clazz != null) { if (resolve) { resolveClass(clazz); } return clazz; } } catch (Throwable e) { } /** * 載入不了跑出異常 */ throw new ClassNotFoundException(); } } }
測試例子:
測試類
package com.stand.job.example;
public class JobServiceTest {
public void run() {
System.out.println("hello world" + getClass().getClassLoader().getClass());
}
}
測試main,在當前測試專案中加入以上jar包,執行以下程式碼
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { File file = new File("/Users/chichaofan/Documents/doc/workspace/example/target/"); File[] files = file.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { if (name.toLowerCase().endsWith(".jar")) { return true; } return false; } }); for (File file2 : files) { StandJobClassLoader jobClassLoader = StandJobClassLoaderFactory.newInstance(false); jobClassLoader.addJar(file2); Object o = jobClassLoader.loadClass("com.stand.job.example.JobServiceTest").newInstance(); ReflectUtils.findMethod(o.getClass(), "run").invoke(o); } }
當delegateLoad為false時輸出
hello worldclass com.stand.job.common.classload.StandJobClassLoader
當delegateLoad為true時輸出
hello worldclass sun.misc.Launcher$AppClassLoader
由此看出當delegateLoad為false時載入器的載入順序被改變了