原文:java classLoader体系结构使用详解
源代码下载地址:http://www.zuidaima.com/share/1774052029516800.htm
jvm classLoader architecture:
类加载器的特性:
类图中, BootstrapClassLoader是一个单独的java类, 其实在这里, 不应该叫他是一个java类。因为,它已经完全不用java实现了。它是在jvm启动时, 就被构造起来的, 负责java平台核心库。
自定义类加载器加载一个类的步骤
classloader-load-class
ClassLoader 类加载逻辑分析, 以下逻辑是除 BootstrapClassLoader 外的类加载器加载流程:
// 检查类是否已被装载过 Class c = findLoadedClass(name); if (c == null ) { // 指定类未被装载过 try { if (parent != null ) { // 如果父类加载器不为空, 则委派给父类加载 c = parent.loadClass(name, false ); } else { // 如果父类加载器为空, 则委派给启动类加载加载 c = findBootstrapClass0(name); } } catch (ClassNotFoundException e) { // 启动类加载器或父类加载器抛出异常后, 当前类加载器将其 // 捕获, 并通过findClass方法, 由自身加载 c = findClass(name); } }
线程上下文类加载器
java默认的线程上下文类加载器是 系统类加载器(AppClassLoader)。
// Now create the class loader to use to launch the application try { loader = AppClassLoader.getAppClassLoader(extcl); } catch (IOException e) { throw new InternalError( "Could not create application class loader" ); } // Also set the context class loader for the primordial thread. Thread.currentThread().setContextClassLoader(loader);
以上代码摘自sun.misc.Launch的无参构造函数Launch()。
使用线程上下文类加载器, 可以在执行线程中, 抛弃双亲委派加载链模式, 使用线程上下文里的类加载器加载类.
典型的例子有, 通过线程上下文来加载第三方库jndi实现, 而不依赖于双亲委派.
大部分java app服务器(jboss, tomcat..)也是采用contextClassLoader来处理web服务。
还有一些采用 hotswap 特性的框架, 也使用了线程上下文类加载器, 比如 seasar (full stack framework in japenese).
线程上下文从根本解决了一般应用不能违背双亲委派模式的问题.
使java类加载体系显得更灵活.
随着多核时代的来临, 相信多线程开发将会越来越多地进入程序员的实际编码过程中. 因此,
在编写基础设施时, 通过使用线程上下文来加载类, 应该是一个很好的选择。
当然, 好东西都有利弊. 使用线程上下文加载类, 也要注意, 保证多根需要通信的线程间的类加载器应该是同一个,
防止因为不同的类加载器, 导致类型转换异常(ClassCastException)。
为什么要使用这种双亲委托模式呢?
java动态载入class的两种方式:
用Class.forName加载类
Class.forName使用的是被调用者的类加载器来加载类的。
这种特性, 证明了java类加载器中的名称空间是唯一的, 不会相互干扰。
即在一般情况下, 保证同一个类中所关联的其他类都是由当前类的类加载器所加载的。
public static Class forName(String className) throws ClassNotFoundException { return forName0(className, true , ClassLoader.getCallerClassLoader()); } /** Called after security checks have been made. */ private static native Class forName0(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException;
上面中 ClassLoader.getCallerClassLoader 就是得到调用当前forName方法的类的类加载器
static块在什么时候执行?
各个java类由哪些classLoader加载?
NoClassDefFoundError和ClassNotFoundException