在此记载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());