ClassLoader

0. 基本问题

//当前使用的classLoader 
Thread.currentThread().getContextClassLoader();		//AppClassLoader

//jvm启动时设置setContextClassLoader
    sun.misc.Launcher.Launcher()

    //查看当前加载了哪些类
    使用java安装目录下的jconsole.exe查看

1.加载器层次关系

bootStrap ClassLoader:加载基类,JAVA_HOME/lib或启动参数-Xbootclasspath指定的路径,按名识别rt.jar
扩展类加载器(Extension ClassLoader):加载JAVA_HOME/lib/ext/目录或系统变量java.ext.dirs指定路径的所有类库(开发可直接使用)。
AppClasLoader应用程序加载器(默认):ClassLoader.getSystemClassLoader()返回的值

2. 双亲委派模型--父类加载(非强制)

双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应当有字节的父类加载器,使用组合的方式(而不是继承)复用父加载器的代码。

工作过程:
一个类加载器收到了类加载请求,它首先不会自己尝试加载这个类,而是把这个请求委托给父类加载器取完成国内,所有加载请求最终都应该传送到顶层的BoootStrap加载器中,只有当父加载器无法完成这个加载请求(父搜索范围中没有找到所需的类),子加载器才尝试自己去加载。

好处:
保证类的唯一性,如类java.lang.Object,它存放在 rt.jar之中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加 载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类

实现-ClassLoader.loadClass:

synchronized (getClassLoadingLock(name)) {
	Class<?> c = findLoadedClass(name);		//是否已加载
	if (c == null) {
		try {
			if (parent != null) {
				c = parent.loadClass(name, false);	//使用父加载器进行加载
			} else {
				c = findBootstrapClassOrNull(name);
			}
		} catch (ClassNotFoundException e) {
		}

		if (c == null) {
			c = findClass(name);	//附加载器无法完成时,自己加载 
									//自定义加载器时重写findClass方法即可
		}
	}
	if (resolve) {
		resolveClass(c);
	}
	return c;
}	

10. 自定义ClassLoader

1). 覆盖上下文的ClassLoader,Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);其它线程继承主进程的classloader,
Java加载类的过程,实质上是调用loadClass()方法,loadClass中调用findLoadedClass()方
法来检查该类是否已经被加载过,如果没有就会调用父加载器的loadClass(),如果父加载器
无法加载该类,就调用findClass()来查找该类。
2). 新建MyClassLoader继承java.lang.ClassLoader,重写其中的findClass()方法。主要是重新设计查找字节码文件的方案,然后调用definedClass来返回。

原文地址:https://www.cnblogs.com/Desneo/p/7227703.html