`
huobengluantiao8
  • 浏览: 1031360 次
文章分类
社区版块
存档分类
最新评论

Java ClassLoader

 
阅读更多


java文件被编译为class文件,成为jvm机器码。jvm通过classloader将class的字节流加载,解析后变为class类。


  1. Bootstrap ClassLoader/启动类加载器
    主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作。
  2. Extension ClassLoader/扩展类加载器
    主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作。
  3. System ClassLoader/系统类加载器
    主要负责java -classpath/-Djava.class.path所指的目录下的类与jar包装入工作。
  4. User Custom ClassLoader/用户自定义类加载器(java.lang.ClassLoader的子类)
    在程序运行期间, 通过java.lang.ClassLoader的子类动态加载class文件, 体现java动态实时类装入特性。
每个时刻,当前类有三种加载器可选择:

系统类加载器, 通过ClassLoader.getSystemClassLoader()

当前类加载器, 加载当前类的加载器。 Class.forName()会隐式调用当前类的加载器加载

当前线程类加载器, 通过Thread.getCurrentThread().getContextClassLoader()获取


加载classloader类的当前类所在的加载器,将会变成classloader的父加载器。


类加载采用双亲代理机制,加载类时,首先代理到父加载器,查找类的顺序变成从根加载器往叶子加载器向下寻找。好处是防止自定义包中实现String类。


每个加载器维护自身的名字空间,父加载器对子加载器可见,反之不可逆。jvm认定一个类,根据类名+加载器。


因为jdk中包含一些API接口类,这些类使用启动类加载器。而其接口实现类在第三方jar包中,采用系统加载类,会导致两边的类无法互相可见,最终导致ClassNotFound异常。解决方法是线程上下文加载器。


java动态载入class的两种方式:

    1) implicit隐式,即利用实例化才载入的特性来动态载入class
    2) explicit显式方式,又分两种方式:
    java.lang.Class的forName()方法
    java.lang.ClassLoader的loadClass()方法
    static块在什么时候执行?
    1)当调用forName(String)载入class时执行,如果调用ClassLoader.loadClass并不会执行.forName(String,false,ClassLoader)时也不会执行.
    2)如果载入Class时没有执行static块则在第一次实例化时执行.比如new ,Class.newInstance()操作
    3)static块仅执行一次

loadClass 为classloader主要方法,传入classname,中间做cache查找、双亲委派、安全控制之类的逻辑,最终返回Class

defineClass , 传入byte字节流,根据jvm的bytecode算法,将其解析为Class


========= tomcat classloader ===========

      Bootstrap
          |
       System
          |
       Common
       /     \
  Webapp1   Webapp2 ...

bootstrap: jvm/lib/ext/*.jar

system: CLASSPATH/*.jar

common: tomcathome/lib/*.jar

webappx: webapp/root/WEB-INF/lib/*.jar webapp/root/WEB-INF/classes/


上图为tomcat加载器树状结构。于双亲委派策略不同的是,WebappClassLoader会优先加载本地的类,然后再委派双亲。(除了servlet api这样的系统类会滤过)

tomcat下线程默认上下文类加载器是 webapp class loader。

因此,应用app中,类的查找顺序是:

/WEB-INF/classes/

/WEB-INF/lib/*.jar

bootstrap

CLASSPATH

tomcathome/lib/



==================== example code =============

// invisible to parent classloader

public class Test {
	public static class A {
    	public A() {
    		System.out.println("Cons A");
    	}
    }
    
    public static void main(String[] args) throws Exception {
    	ClassLoader cl = Thread.currentThread().getContextClassLoader();
    	ClassLoader pcl = cl.getParent();
    	pcl.loadClass(Object.class.getName()); // ok to load root class
    	pcl.loadClass(A.class.getName()); // fail to load child class, throw java.lang.ClassNotFoundException: Test$A
    }
}

// thread context classloader

public class Test {
	public static class A {
		public A() {
			System.out.println("Cons A");
		}
	}

	public static void main(String[] args) throws Exception {
		ClassLoader cl = Thread.currentThread().getContextClassLoader();
		ClassLoader pcl = cl.getParent();
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				ClassLoader cl = Thread.currentThread().getContextClassLoader();
				try {
					new A(); // ok, 使用当前类加载器加载A
					Class.forName(A.class.getName()); // ok, 使用当前类加载器加载A
					ClassLoader.getSystemClassLoader().loadClass(A.class.getName()); // ok,
																					 // 使用系统类加载器
					cl.loadClass(A.class.getName()); // throw ex, A class not
													 // found
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
		});
		t.setContextClassLoader(pcl);
		t.start();
		t.join();
	}
}


// static block execute time

public class Test {
	public static class A {
		static {
			System.out.println("static");
		}
		public A() {
			System.out.println("Cons A");
		}
	}

	public static void main(String[] args) throws Exception {
		Thread.currentThread().getContextClassLoader().loadClass(A.class.getName()); // no static exec
		System.out.println("load class");
		Class.forName(A.class.getName(), false, ClassLoader.getSystemClassLoader()); // no static exec
		System.out.println("class for name0");
		Class.forName(A.class.getName()); // static exec
		System.out.println("class for name1");
		System.out.println("~~~~~~ new A");
		new A();
	}
}
---------------------- result: -------------------

load class
class for name0
static
class for name1
~~~~~~ new A
Cons A




分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics