- 加载类信息:
@Slf4j
public class ClassLoadUtil {
public static Class<?> loadClass(String classPath, String className) {
MyClassLoader loader = new MyClassLoader(classPath);
return loader.findClass(className);
}
private static class MyClassLoader extends ClassLoader {
/**
* 需要加载类的路径,E:\Hello.class
*/
private final String classPath;
public MyClassLoader(String classPath) {
super();
this.classPath = classPath;
}
@Override
protected Class<?> findClass(String className) {
Class<?> clazz = null;
// 获取class文件字节码数组
byte[] clazzByteArr = getData();
if (clazzByteArr != null) {
// 将class的字节码数组转换成class类的实例
clazz = defineClass(className, clazzByteArr, 0, clazzByteArr.length);
}
return clazz;
}
/**
* 获取class文件字节数组
* @return 字节码
*/
private byte[] getData() {
File file = new File(this.classPath);
if (file.exists()) {
try (FileInputStream in = new FileInputStream(file)) {
return IOUtils.toByteArray(in);
} catch (IOException e) {
log.error("读取文件异常:", e);
}
}
return null;
}
}
}
- Bean容器工具类:
@Component
public class SpringContextUtil implements BeanFactoryAware {
public static DefaultListableBeanFactory listableBeanFactory;
@Override
public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException {
listableBeanFactory = (DefaultListableBeanFactory) beanFactory;
}
public static <T> void registerSingleton(Class<T> type) {
T obj = listableBeanFactory.createBean(type);
String beanName = beanName(type.getName());
listableBeanFactory.registerSingleton(beanName, obj);
}
public static void destroy(String className) {
String beanName = beanName(className);
listableBeanFactory.destroySingleton(beanName);
}
public static String beanName(String className){
String[] path = className.split("\\.");
String beanName = path[path.length - 1];
return Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);
}
@SuppressWarnings("unchecked")
public static <T> T getBean(String name){
return (T) listableBeanFactory.getBean(name);
}
public static <T> T getBean(Class<T> type) {
return listableBeanFactory.getBean(type);
}
public static <T> Map<String, T> getBeans(Class<T> type) {
return listableBeanFactory.getBeansOfType(type);
}
}
- 测试:
每次加载类信息时,先卸载旧的Class,当然已有的Bean也要卸载,要卸载Bean,必须也要把类加载器卸载掉。JVM判断类卸载的条件是:
1.该class的引用和实例已经不存在;
2.classLoader已经不存在;
@SneakyThrows
public void testBean(String classPath, String className) {
//销毁Bean
SpringContextUtil.destroy(className);
//每次都是new新的ClassLoader对象
Class<?> type = ClassLoadUtil.loadClass(classPath, className);
SpringContextUtil.registerSingleton(type);
String beanName = SpringContextUtil.beanName(className);
Object obj = SpringContextUtil.getBean(beanName);
Method m = type.getMethod("test", String.class);
m.invoke(obj, beanName);
}
@Slf4j
public class BeanTest {
public void test(String name) {
log.info("Hello,Hello,Hello,Hello,{}", name);
}
}
接口测试一下: