1、java本身的三个ClassLoader
BootClassLoader
(baidu:Bootstrp加载器是用C++语言写的,它是在Java虚拟机启动后初始化的,它主要负责加载%JAVA_HOME%/jre/lib
,-Xbootclasspath
参数指定的路径以及%JAVA_HOME%/jre/classes
中的类)
|
ExtClassLoader
(baidu:Bootstrp loader加载ExtClassLoader,并且将ExtClassLoader的父加载器设置为Bootstrp loader.ExtClassLoader是用Java写的,具体来说就是 sun.misc.Launcher$ExtClassLoader,ExtClassLoader主要加载%JAVA_HOME%/jre/lib/ext
,此路径下的所有classes目录以及java.ext.dirs
系统变量指定的路径中类库)
|
AppClassLoader
(baidu:Bootstrp loader加载完ExtClassLoader后,就会加载AppClassLoader,并且将AppClassLoader的父加载器指定为 ExtClassLoader。AppClassLoader也是用Java写成的,它的实现类是 sun.misc.Launcher$AppClassLoader,主要负责加载classpath所指定的位置的类或者是jar文档,它也是Java程序默认的类加载器, Thread.currentThread().getContextClassLoader() 就是它,
ClassLoader.getSystemClassLoader() 也是它)
2、自定义个ClassLoader ,用于其它目的
public class BSClassLoader extends URLClassLoader {
private final String JAR_SUFFIX = ".jar";
private final String FILE_PROTOCOL = "file";
private final String SLASH = "/";
private final String ESCAPE_SEPARATOR = "\\";
public BSClassLoader () {
this(new URL[] {},Thread.currentThread().getContextClassLoader());
}
public BSClassLoader (ClassLoader parent) {
this(new URL[] {}, parent);
}
public BSClassLoader (URL[] urls) {
super(urls);
}
public BSClassLoader (URL[] urls, ClassLoader parent) {
super(urls, parent);
}
public Class<?> findInternalClass(String name) {
return findLoadedClass(name);
}
public void addJarsDir(String path) {
File pathFile = new File(path);
if (!pathFile.exists()) {
return;
}
if (!pathFile.isDirectory()) {
return;
}
File[] jarFiles = pathFile.listFiles();
for (File jarFile : jarFiles) {
String fileName = jarFile.getName();
if (fileName.endsWith(JAR_SUFFIX)) {
addJar(jarFile);
} else {
continue;
}
}
}
public void addJar(File file) {
String repositoryPath = file.getAbsolutePath();
repositoryPath = PathUtils.transformToCanonical(repositoryPath);
addRepository(repositoryPath, false);
}
public void addClassDir(String path) {
File pathFile = new File(path);
if (!pathFile.exists()) {
return;
}
if (!pathFile.isDirectory()) {
return;
}
path = PathUtils.transformToCanonical(path);
addRepository(path, true);
}
private void addRepository(String path, boolean slash) {
try {
path = path.replace(ESCAPE_SEPARATOR, SLASH);
if (slash) {
if (!path.endsWith(SLASH)) {
path = path.concat(SLASH);
}
}
URL url = new URL(FILE_PROTOCOL, null, path);
addURL(url);
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
}
public abstract class PathUtils {
private final static String ESCAPE_SEPARATOR = "\\";
private final static String CANONICAL_SEPARATOR = "/";
public static String transformToCanonical(String path) {
if (StringUtils.isBlank(path)) {
return path;
} else {
return path.replace(ESCAPE_SEPARATOR, CANONICAL_SEPARATOR);
}
}
}
3、使用系统AppClassLoader :
//自定义包
public class AppClassLoader {
private final String JAR_SUFFIX = ".jar";
private final String FILE_PROTOCOL = "file";
private final String METHOD = "addURL";
private final String SLASH = "/";
private final String ESCAPE_SEPARATOR = "\\";
private URLClassLoader loader;
private Method method;
public AppClassLoader() {
try {
loader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
method = URLClassLoader.class.getDeclaredMethod(METHOD, new Class[] { URL.class });
method.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loader.loadClass(name);
}
public void addJarsDir(String path) {
File pathFile = new File(path);
if (!pathFile.exists()) {
return;
}
if (!pathFile.isDirectory()) {
return;
}
File[] jarFiles = pathFile.listFiles();
for (File jarFile : jarFiles) {
String fileName = jarFile.getName();
if (fileName.endsWith(JAR_SUFFIX)) {
addJar(jarFile);
} else {
continue;
}
}
}
public void addJar(File file) {
String repositoryPath = file.getAbsolutePath();
repositoryPath = PathUtils.transformToCanonical(repositoryPath);
addRepository(repositoryPath, false);
}
public void addClassDir(String path) {
File pathFile = new File(path);
if (!pathFile.exists()) {
return;
}
if (!pathFile.isDirectory()) {
return;
}
path = PathUtils.transformToCanonical(path);
addRepository(path, true);
}
private void addRepository(String path, boolean slash) {
try {
path = path.replace(ESCAPE_SEPARATOR, SLASH);
if (slash) {
if (!path.endsWith(SLASH)) {
path = path.concat(SLASH);
}
}
URL url = new URL(FILE_PROTOCOL, null, path);
method.invoke(loader, new Object[] { url });
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
4、使用
如果BootClassLoader 使用不好,可以试试AppClassLoader
BootClassLoader 用不好,一定是你对jvm 的ClassLoader双亲委派机制没理解好,那就用这个万能的AppClassLoader
BootClassLoader loader = new BootClassLoader();
//AppClassLoader loader = new AppClassLoader ();
String appHome = "f://a/b/server"
String repertory1 = appHome.concat("/webapp/WEB-INF/classes");
String repertory2 = appHome.concat("/webapp/WEB-INF/lib");
String repertory3 = appHome.concat("/lib");
loader.addClassDir(repertory1);
loader.addJarsDir(repertory2);
loader.addJarsDir(repertory3);
try {
Class<?> server = loader.loadClass("com.bs.Server");
Method method = server.getMethod("start");
method.setAccessible(true);
method.invoke(server.newInstance());
} catch (Exception e) {
throw new RuntimeException(e);
}
关键代码,自定义启停脚本,你可自行先琢磨