在此記載Java動態重新加載Class的點點滴滴,實現之前也在網上看了很多文章,但發現不是很清晰,后來發現總結,看源碼實現還是最靠譜。
直接上代碼:
package com.lkb.autoCode.util; import com.lkb.autoCode.constant.AutoCodeConstant; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; /** * DynamicClassLoader 動態類加載器 * * @author Lilin * @date 2016/5/23 */ public class DynamicClassLoader extends ClassLoader { private String classPath; public DynamicClassLoader(String classPath, ClassLoader parent) { super(parent); this.classPath = classPath; } @Override public Class<?> loadClass(String name) throws ClassNotFoundException { // 判斷當前加載的類是否是需要動態重新加載的類, // 假如是通過重寫的findClass在自定義的ClassLoader里面加載, // 假如不是就調用父ClassLoader默認加載 if (name != null && name.equals(classPath)) { return findClass(name); } return super.loadClass(name, false); } /** * 根據類名查找class * * @param fullClassPath 類全路徑(包) * @return * @throws ClassNotFoundException */ @Override protected Class<?> findClass(String fullClassPath) throws ClassNotFoundException { byte[] raw = readClassBytes(fullClassPath); // definClass方法參數說明:name:類包的全路徑如com.lkb.sb.client.shanghaiC.ShangHaiLoginClient // b:讀取的class文件的byte數組 // off:從byte數組中讀取的索引 // len:從byte數組中讀取的長度 // 注:假如此類中有引入別的class類,如com.lkb.sb.client.BaseClient,循環執行findClass方法 Class<?> clazz = defineClass(fullClassPath, raw, 0, raw.length); // 連接class resolveClass(clazz); return clazz; } /** * 讀取class * * @param fullClassPath * @return */ private byte[] readClassBytes(String fullClassPath) { byte[] raw = null; InputStream stream = null; try { File file = new File(AutoCodeConstant.BASE_PATH + fullClassPath.replaceAll("\\.", "/") + AutoCodeConstant.CLASS_SUFFIX); stream = new FileInputStream(file); raw = new byte[(int) file.length()]; stream.read(raw); } catch (Exception e) { } finally { try { stream.close(); } catch (Exception e) { } } return raw; } }
注:調用方式:
// 通過自定義類加載器來加載 // 獲取類的完成路徑 String fullClassPath = getFullClassPath(AutoCodeConstant.CLIENT_PACKAGE, provinceCode, cityCode, AutoCodeConstant.LOGIN_CLIENT); // 父ClassLoader設為當前線程的ClassLoader,試過使用ClassLoader.getSystemClassLoader(),發現獲取的是系統級的,懶加載的類找不到 dynamicClassLoader = new DynamicClassLoader(fullClassPath, Thread.currentThread().getContextClassLoader()); loginInterface = (LoginInterface) dynamicClassLoader.loadClass(fullClassPath).getConstructor(new Class[]{CommonLoginSb.class, SbDefultModel.class}).newInstance(new Object[]{commonLoginSb, sbDefultModel}); // 執行start方法 resOutput = loginInterface.start(commonLoginSb.getMethod());