import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Objects;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* @title CustomClassLoader
* @description 自定义类加载器
* author zzw
* version 1.0.0
* create 2024/8/18 01:34
**/
@Slf4j
public class CustomClassLoader extends URLClassLoader {
private JarFile jarFile;
private ClassLoader parent;
public CustomClassLoader(URL[] urls, JarFile jarFile, ClassLoader parent) {
super(urls, parent);
this.jarFile = jarFile;
this.parent = parent;
}
public CustomClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
/**
* 将类的全限定名替换成类路径
* com.doudou.thread.Test003 -> com/doudou/thread/Test003.class
*
* @param name 类的全限定名
* @return
*/
private static String classNameToJarEntry(String name) {
String classPath = name.replaceAll("\\.", "\\/");
return new StringBuilder(classPath).append(".class").toString();
}
/**
* 重新loadClass方法,按照类包路径加载Class到JVM
*
* @param name 类全限定名
* @param resolve
* @return
* @throws ClassNotFoundException
*/
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
// 自定义类的加载规则,和findClass方法一起组合打破双亲委派
// 如果类所在的包是以com.xx或com.yyy起始的,使用自定义加载方法进行类加载
if (name.startsWith("com.xx") || name.startsWith("com.yyy")) {
return this.findClass(name);
}
// 其它的使用双亲委派机制进行类加载
return super.loadClass(name, resolve);
}
/**
* 进行类的查找以及加载
*
* @param name 类的全限定名
* @return 加载到的类
* @throws ClassNotFoundException
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class clazz = null;
try {
// 将类的全限定名转换成该类在类路径(jar包)中的路径
String jarEntryName = classNameToJarEntry(name);
// 自定义加载类是加载指定jar中的类,因此JarFile不存在时直接返回null
if (Objects.isNull(jarFile)) {
return clazz;
}
// 在jar包中找到指定类的信息
JarEntry jarEntry = jarFile.getJarEntry(jarEntryName);
// 找到类信息的情况下,将类信息转换为字节数组,并加载成class
if (Objects.nonNull(jarEntry)) {
InputStream inputStream = jarFile.getInputStream(jarEntry);
byte[] bytes = IOUtils.toByteArray(inputStream);
clazz = defineClass(name, bytes, 0, bytes.length);
}
} catch (IOException e) {
log.info("Custom classloader load calss {} failed", name);
}
return clazz;
}
}
11-25
1032
11-10
4555
07-25
735
11-07