
编写要加载/卸载的测试jar
package cn.com.test;
public class JarTest {
static {
System.out.println("I am JarTest's static code");
}
public static void run(){
System.out.println("I am JarTest's static method");
}
public void run1(){
System.out.println("I am JarTest's method>>>"+this);
}
}将以上class 打包成jartest.jar 假定打包文件位置放在/Users/tmp/jartest.jar
使用jar -cvf jartest.jar **path 打包或者使用IDE打包都行
编写加载/卸载测试工具
package jar;
import sun.misc.ClassLoaderUtil;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class LoadJar {
static Object jarTestInstance = null;
static ClassLoader myClassLoader1;
static Class<?> jarTest;
public static void main(String[] args) throws MalformedURLException, InterruptedException {
System.out.println("befor laod jar");
loadClassAndRun();
Thread.sleep(1000);
System.out.println("laod jar");
loadJar();
Thread.sleep(1000);
System.out.println("after load jar");
loadClassAndRun();
Thread.sleep(1000);
System.out.println("start unload jar");
unLoad();
Thread.sleep(1000);
System.out.println("after unload jar");
loadClassAndRun();
System.out.println("laod jar");
loadJar();
Thread.sleep(1000);
System.out.println("after load jar");
loadClassAndRun();
}
private static void loadClassAndRun() {
if(myClassLoader1 == null) {
myClassLoader1 = LoadJar.class.getClassLoader();
}
try {
jarTest = myClassLoader1.loadClass("cn.com.test.JarTest");
jarTestInstance = jarTest.newInstance();
for (Method method : jarTest.getMethods()) {
try {
method.invoke(jarTestInstance);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
}
private static void loadJar() throws MalformedURLException {
URL url = new File("/Users/tmp/jartest.jar").toURI().toURL();
myClassLoader1 = new URLClassLoader(new URL[] { url});
}
// 卸载jar包的代码如下:
public static void unLoad() {
if (null != myClassLoader1 && myClassLoader1 instanceof URLClassLoader) {
System.out.println("unload URLClassLoader ");
URLClassLoader loader = (URLClassLoader) myClassLoader1;
try {
// 关注下这里,这里一会儿要改
ClassLoaderUtil.releaseLoader(loader);
loader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
URLClassLoader.close()释放掉资源后,刚加载过的class仍然可以继续使用? 官方解释:

*** 从官方的解释中来看,确实如此 *** 那么在什么时候会被回收呢? 反思类的加载机制,类在没有引用时可被GC,改动unLoad() 方法如下:
// 卸载jar包的代码如下:
public static void unLoad() {
if (null != myClassLoader1 && myClassLoader1 instanceof URLClassLoader) {
System.out.println("unload URLClassLoader ");
URLClassLoader loader = (URLClassLoader) myClassLoader1;
try {
jarTest = null;
jarTestInstance = null;
myClassLoader1 = null;
System.gc();
Thread.sleep(2000);
ClassLoaderUtil.releaseLoader(loader);
loader.close();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}再次测试:

需要注意的是GC不是立即执行的,可能你的验证结果跟我不一样,注意区分!