由于应用局限,一个classloader只加载一个jar包,所以代码为:
这是一个包装类:
public class MyClassLoader {
@Resource
private SystemConfig systemConfig;
private final static ConcurrentHashMap<String,MyURLClassLoader> LOADER_CACHE = new ConcurrentHashMap<>();
// private MyURLClassLoader urlClassLoader;
public void loadJar(String jarName) throws MalformedURLException {
MyURLClassLoader urlClassLoader = LOADER_CACHE.get(jarName);
if(urlClassLoader!=null){
return;
}
urlClassLoader = new MyURLClassLoader();
// String path = systemConfig.getExternalClassPath();
String path = "E:/testspace/externalClassPath";
URL jarUrl = new URL("jar:file:/"+path+"/"+jarName+"!/");
urlClassLoader.addURLFile(jarUrl);
LOADER_CACHE.put(jarName,urlClassLoader);
}
public Class loadClass(String jarName,String name) throws ClassNotFoundException {
MyURLClassLoader urlClassLoader = LOADER_CACHE.get(jarName);
if(urlClassLoader==null){
return null;
}
return urlClassLoader.loadClass(name);
}
public void unloadJarFile(String jarName) throws MalformedURLException {
MyURLClassLoader urlClassLoader = LOADER_CACHE.get(jarName);
if(urlClassLoader==null){
return;
}
// String path = systemConfig.getExternalClassPath();
String path = "E:/testspace/externalClassPath";
String jarStr = "jar:file:/"+path+"/"+jarName+"!/";
urlClassLoader.unloadJarFile(jarStr);
urlClassLoader = null;
LOADER_CACHE.remove(jarName);
}
}
以下是真正运行的classloader:
public class MyURLClassLoader extends URLClassLoader {
private JarURLConnection cachedJarFile = null;
public MyURLClassLoader() {
super(new URL[] {}, findParentClassLoader());
}
/**
* 将指定的文件url添加到类加载器的classpath中去,并缓存jar connection,方便以后卸载jar
* 一个可想类加载器的classpath中添加的文件url
* @param
*/
public void addURLFile(URL file) {
try {
// 打开并缓存文件url连接
URLConnection uc = file.openConnection();
if (uc instanceof JarURLConnection) {
uc.setUseCaches(true);
((JarURLConnection) uc).getManifest();
cachedJarFile = (JarURLConnection)uc;
}
} catch (Exception e) {
System.err.println("Failed to cache plugin JAR file: " + file.toExternalForm());
}
addURL(file);
}
public void unloadJarFile(String url){
JarURLConnection jarURLConnection = cachedJarFile;
if(jarURLConnection==null){
return;
}
try {
System.err.println("Unloading plugin JAR file " + jarURLConnection.getJarFile().getName());
jarURLConnection.getJarFile().close();
jarURLConnection=null;
// System.gc();
} catch (Exception e) {
System.err.println("Failed to unload JAR file\n"+e);
}
}
/**
* 定位基于当前上下文的父类加载器
* @return 返回可用的父类加载器.
*/
private static ClassLoader findParentClassLoader() {
ClassLoader parent = MyURLClassLoader.class.getClassLoader();
if (parent == null) {
parent = MyURLClassLoader.class.getClassLoader();
}
if (parent == null) {
parent = ClassLoader.getSystemClassLoader();
}
return parent;
}
}
使用以上代码可以实现jar包、类的热替换,使用方法:
public class Test {
public static void main(String[] args) {
MyClassLoader classLoader = new MyClassLoader();
while (true) {
try {
classLoader.loadJar("creatoo-demo-1.0-SNAPSHOT.jar");
Class clz = classLoader.loadClass("creatoo-demo-1.0-SNAPSHOT.jar","com.creatoo.core.impl.CreatooServiceImpl");
ParameterTranlate parameterTranlate = (ParameterTranlate) clz.newInstance();
String input = parameterTranlate.getBookInput("sdf");
System.out.println(input);
Thread.sleep(1000);
classLoader.unloadJarFile("creatoo-demo-1.0-SNAPSHOT.jar");
// System.gc();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}