`
elgs
  • 浏览: 8945 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
社区版块
存档分类
最新评论

再谈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在这个例子里。

现在已经没有什么阻止我们自己做出一个应用服务器了。
0
0
分享到:
评论

相关推荐

    ClassLoader运行机制 自己写的

    在Java虚拟机(JVM)中,类加载器(ClassLoader)是至关重要的组成部分,它负责查找和加载类的字节码文件。理解ClassLoader的工作机制对于深入掌握Java应用程序的运行至关重要。这里我们将详细讨论ClassLoader的运行...

    classloader

    这篇教程将对Java ClassLoader进行概述,并指导你构建一个示例ClassLoader,该ClassLoader可以自动编译代码后再加载。学习ClassLoader的工作原理以及如何创建自己的ClassLoader是必要的。 首先,让我们深入了解...

    ClassLoader

    ### Java虚拟机中ClassLoader概述与双亲委托机制详解 #### 一、ClassLoader概念与作用 在Java编程语言中,`ClassLoader`是一个非常重要的组件,它负责加载程序运行所需的类文件到Java虚拟机(JVM)中。`ClassLoader`...

    自定义classloader的使用

    在Java中,Classloader是加载类的关键组件,它负责查找、加载和初始化字节码文件。自定义Classloader允许开发者根据特定需求定制类的加载逻辑,例如加密类文件、隔离不同版本的库或者动态加载代码。本文将深入探讨...

    Java ClassLoader定制实例

    在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中。理解ClassLoader的工作原理以及如何定制它,对于深入学习Java的运行机制和进行高级应用开发具有重要意义。本篇文章将...

    ClassLoader小例子

    - Java的类加载机制遵循“双亲委派模型”,即一个类加载请求会先由顶级的Bootstrap ClassLoader处理,如果没有找到,则交给Extension ClassLoader,再未找到则继续交给App ClassLoader,最后是用户自定义的...

    ClassLoader类加载机制和原理详解

    当一个类被加载时,它首先会尝试由当前线程的Context ClassLoader进行加载,如果该类加载器无法加载,则向上委托给父类加载器,直至Bootstrap ClassLoader。这种设计可以避免类的重复加载,同时保证核心库的稳定性和...

    java ClassLoader机制及其在OSGi中的应用

    Java ClassLoader机制是Java虚拟机(JVM)中一个至关重要的组成部分,它的主要任务是将类的.class文件加载到JVM中,使得程序能够运行。ClassLoader不仅负责类的加载,还涉及类的验证、初始化等一系列过程。理解...

    深入理解ClassLoader工作机制.docx

    《深入理解ClassLoader工作机制》 Java虚拟机(JVM)中的ClassLoader是负责加载类到内存中的核心组件。它不仅承担着将字节码转换为可执行对象的重任,还参与了类生命周期的各个阶段,包括加载、验证、准备、解析、...

    JVM ClassLoader简析

    首先,ClassLoader可以分为三种基本类型:Bootstrap ClassLoader、Extension ClassLoader和Application ClassLoader。Bootstrap ClassLoader是JVM启动时的第一个ClassLoader,负责加载JDK的`&lt;JAVA_HOME&gt;\lib`目录下...

    ClassLoader 详解.doc

    《ClassLoader详解》 Java应用程序的运行离不开类的加载,而ClassLoader正是这个过程的关键角色。它负责将类的字节码加载到Java虚拟机(JVM)中并转换为可执行的Java对象。深入理解ClassLoader的工作原理对于优化...

    理解Java ClassLoader机制

    Java ClassLoader机制是Java运行时环境中的核心组件之一,它负责加载类到JVM(Java虚拟机)中,使得程序能够执行。理解ClassLoader的工作原理对于优化应用性能、处理类加载问题以及实现自定义加载器至关重要。 首先...

    ClassLoader 案例

    在Java编程语言中,ClassLoader是核心组件之一,它负责加载类到JVM(Java虚拟机)中。自定义ClassLoader允许开发者根据特定需求加载类,比如动态加载或更新类文件,这在某些高级应用场景中非常有用,如插件系统、热...

    java classloader

    Java ClassLoader是一个核心的Java运行时组件,负责加载类到Java虚拟机(JVM)中。它是Java平台的独特特性,因为它允许动态加载类,增强了软件的可扩展性和灵活性。这篇博文(虽然链接不可用)可能深入探讨了...

    破解java加密的ClassLoader.java,在classloader植入破解代码

    破解java加密的ClassLoader.java,在classloader植入破解代码

    ClassLoader的 一些测试

    在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中执行。这篇测试主要探讨了ClassLoader的工作原理及其在实际应用中的使用。通过阅读给出的博文链接,我们可以深入理解...

Global site tag (gtag.js) - Google Analytics