我是靠谱客的博主 动人狗,最近开发中收集的这篇文章主要介绍再谈ClassLoader(CurrentClassLoader, ParentClassLoader and ContextClassLoader),觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
受到Tomcat的Catalina的Lifecycle和Container接口的启发,一直想写一个自己的应用服务器,让多个应用在各自的classpath中独立运行,但一直被CurrentClassLoader, ParentClassLoader和ContextClassLoader 所困惑,现在终于弄清楚他们的关系了,希望和大家分享。
我的想法是整个应用服务器被一段类似如下的xml所配置:
<App name="Server">
<App name="s1" path="...">
<App name="s1_1" path="..." />
</App>
<App name="s2" path="...">
<App name="s2_1" path="..." />
</App>
</App>
每一个App都是一个应用,同时也是一个容器,最顶上的App就是这个应用服务器本身。应用服务器本身和应用是完全平等的,每个外层的容器(应用)递归地负责内层所有容器(应用)的生命周期。
path所对应的目录下应该有两个子目录,分别是lib和classes,这两个目录定义了这个应用的classpath,应用之间互相看不到其他应用的classpath,仅内层应用可以看到外层的。
一个问题是,如何启动一个线程,让这个线程里运行的代码从指定的ClassLoader查找类的定义。
为了解决这个问题,我们来看一些代码。我们用下面这三个方法从一个路径生成一个URLClassLoader:
private static ClassLoader createClassLoader(String path) throws Exception {
List<File> jarList = new ArrayList<File>();
getClassPath(jarList, new Filter(), new File(path, "lib"));
List<URL> urlList = new ArrayList<URL>();
urlList.add(new URL("file:///" + path + "/classes/"));
for (int i = 0; i < jarList.size(); ++i) {
urlList.add(new URL("file:///"
+ ((File) jarList.get(i)).getCanonicalPath()));
}
return new URLClassLoader((URL[]) urlList.toArray(new URL[0]), Thread
.currentThread().getContextClassLoader());
}
private static void getClassPath(List<File> list, Filter filter, File f) {
if (f.exists() && f.isDirectory()) {
File[] ss = f.listFiles(filter);
for (int i = 0; i < ss.length; ++i) {
if (ss[i].isFile()) {
list.add(ss[i]);
} else if (ss[i].isDirectory()) {
getClassPath(list, filter, ss[i]);
}
}
}
}
private static class Filter implements FilenameFilter {
public boolean accept(File dir, String name) {
File f = new File(dir, name);
boolean isDir = f.isDirectory();
boolean isFile = f.isFile();
boolean isJar = name.toLowerCase().endsWith(".jar");
boolean isZip = name.toLowerCase().endsWith(".zip");
return (isFile && (isJar || isZip)) || isDir;
}
}
createClassLoader方法从path目录下的lib和classes两个目录下找到类的定义,并返回对应的URLClassLoader。这是第一步。
接下来我们需要启动一个线程(模拟一个App),让这个线程中运行的代码到createClassLoader返回的ClassLoader的classpath中查找类的定义,并且设置新线程(App)的ParentClassLoader成启动这个线程的线程当前ClassLoader,和设置新线程(App)的ContextClassLoader成createClassLoader返回的ClassLoader。我们先看新线程(App)的代码:
package test;
public class T extends Thread {
public void run() {
System.out.println("App context: "
+ Thread.currentThread().getContextClassLoader());
System.out.println("App parent: "
+ this.getClass().getClassLoader().getParent());
System.out.println("App current: " + this.getClass().getClassLoader());
}
}
最后用一段代码调用启动这个测试程序:
public static void main(String[] args) throws Exception {
ClassLoader appClassLoader = createClassLoader("D:/P/eclipse/workspace/TestApp");
Class c = appClassLoader.loadClass("test.T");
Object t = c.newInstance();
Method setContextClassLoader = c.getMethod("setContextClassLoader",
new Class[] { ClassLoader.class });
setContextClassLoader.invoke(t, appClassLoader);
Method start = c.getMethod("start", new Class[] {});
start.invoke(t, new Object[] {});
System.out.println("Main context: "
+ Thread.currentThread().getContextClassLoader());
System.out.println("Main current: " + Test.class.getClassLoader());
System.out.println("Main parent: "
+ Test.class.getClassLoader().getParent());
System.out.println("App ClassLoader: " + appClassLoader);
System.out.println("Systen ClassLoader: "
+ ClassLoader.getSystemClassLoader());
}
输出的结果是:
Main context: sun.misc.Launcher$AppClassLoader@11b86e7
Main current: sun.misc.Launcher$AppClassLoader@11b86e7
Main parent: sun.misc.Launcher$ExtClassLoader@35ce36
App ClassLoader: java.net.URLClassLoader@addbf1
Systen ClassLoader: sun.misc.Launcher$AppClassLoader@11b86e7
App context: java.net.URLClassLoader@addbf1
App parent: sun.misc.Launcher$AppClassLoader@11b86e7
App current: java.net.URLClassLoader@addbf1
其中Main代表外层容器,App代表内层容器。我们发现,这个时候App的ContextClassLoader和CurrentClassLoader都已经是我们用createClassLoader方法生成的ClassLoader了,而它的ParentClassLoader是外层容器的CurrentClassLoader,是SystemClassLoader在这个例子里。
现在已经没有什么阻止我们自己做出一个应用服务器了。
最后
以上就是动人狗为你收集整理的再谈ClassLoader(CurrentClassLoader, ParentClassLoader and ContextClassLoader)的全部内容,希望文章能够帮你解决再谈ClassLoader(CurrentClassLoader, ParentClassLoader and ContextClassLoader)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复