自定义URLClassLoader 加载指定class

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);
        }

关键代码,自定义启停脚本,你可自行先琢磨

猜你喜欢

转载自my.oschina.net/u/1434882/blog/1787370