java类加载器-系统类加载器
系统类加载器
系统类加载器可能都耳详能熟,但是为了完整点,还是先简单的说说系统的类加载器吧。
public class Test {
public static void main(String[] args) {
ClassLoader cl1 = Test.class.getClassLoader().getParent().getParent();
System.out.println(cl1);
ClassLoader cl2 = Test.class.getClassLoader().getParent();
System.out.println(cl2);
ClassLoader cl3 = Test.class.getClassLoader();
System.out.println(cl3);
}
}
打印的结果是:
null
sun.misc.Launcher$ExtClassLoader@dc6a77
sun.misc.Launcher$AppClassLoader@1016632
其实这就是jdk系统中用到的三个类加载器,其中null就是bootstrap classloader,因为是有c++实现,所以在此打印出null。ExtClassLoader就是Extension ClassLoader。AppClassLoader就是App ClassLoader或者叫做system classloader。他们负责加载各自指定位置下的类:
1)Bootstrap ClassLoader
负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类
2)Extension ClassLoader
负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包
3)App ClassLoader
负责加载classpath中指定的jar包及目录中class
这三个类加载器的关系通过代码就能看出来:App ClassLoader的parent是Extension ClassLoader,Extension ClassLoader的parent是Bootstrap ClassLoader。
委托机制
所谓委托机制就是,当加载一个类时,App ClassLoader委托他的parent(Extension ClassLoader)去加载,Extension ClassLoader又委托他的parent加载直到Bootstrap ClassLoader,如果parent没有加载成功,再由自身去加载。
以上三个类加载器,除了Bootstrap ClassLoader都是间接继承自ClassLoader类(是一个抽象类不能实例化,但没有抽象方法),委托机制的实现就被loadClass方法作为模板方法实现。以下就通过loadClass的源码分析一下委托机制:

定制类加载器
有时我们可能需要定制我们的类加载器以满足我们的特殊需求。而且我们一般也不需要破坏委托机制(后边会介绍一个破坏了委托机制的类加载器的例子)通常可以有两种方法实现
一、继承URLClassLoader,比如
public class TestClassLoader extends URLClassLoader {
public TestClassLoader(URL[] urls) {
super(urls);
}
public TestClassLoader(URL[] urls,ClassLoader parent) {
super(urls,parent);
}
}
你只需要调用父类构造方法,其它方法你一概不用重写。这也是最简单的实现。使用时只需要调用loadClass。缺点是你只能通过URL定位你要加载的class。
二、继承ClassLoader类,重写findClass方法。比如
public class TestClassLoader extends ClassLoader {
private String basedir;
public TestClassLoader(String basedir,ClassLoader parent){
super(parent);
this.basedir = basedir;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> cls = null;
StringBuffer sb = new StringBuffer(basedir);
String classname = name.replace('.', File.separatorChar) + ".class";
sb.append(File.separator + classname);
File classF = new File(sb.toString());
if(!classF.exists()){
throw new ClassNotFoundException();
}
byte[] raw = new byte[(int) classF.length()];
try {
InputStream fin = new FileInputStream(classF);
fin.read(raw);
fin.close();
} catch (Exception e) {
e.printStackTrace();
}
cls = defineClass(name,raw,0,raw.length);
return cls;
}
}
在findClass方法里我们可以采用任意方式查找我们要加载的类,这里采用了读文件的方式。使用时同样是调用loadClass方法。
线程上下文类加载器
线程上下文类加载器(context class loader)是从 JDK 1.2 开始引入的。类 java.lang.Thread中的方法 getContextClassLoader()和setContextClassLoader(ClassLoader cl)用来获取和设置线程的上下文类加载器。如果没有通过 setContextClassLoader(ClassLoader cl)方法进行设置的话,线程将继承其父线程的上下文类加载器。Java 应用运行的初始线程的上下文类加载器是系统类加载器。在线程中运行的代码可以通过此类加载器来加载类和资源。
前面提到的类加载器的委托机制并不能解决 Java 应用开发中会遇到的类加载器的全部问题。Java 提供了很多服务提供者接口(Service Provider Interface,SPI),允许第三方为这些接口提供实现。常见的 SPI 有 JDBC、JCE、JNDI、JAXP 和 JBI 等。这些 SPI 的接口由 Java 核心库来提供,如 JAXP 的 SPI 接口定义包含在 javax.xml.parsers包中。这些 SPI 的实现代码很可能是作为 Java 应用所依赖的 jar 包被包含进来,可以通过类路径(CLASSPATH)来找到,如实现了 JAXP SPI 的 Apache Xerces所包含的 jar 包。SPI 接口中的代码经常需要加载具体的实现类。如 JAXP 中的 javax.xml.parsers.DocumentBuilderFactory类中的 newInstance()方法用来生成一个新的 DocumentBuilderFactory的实例。这里的实例的真正的类是继承自 javax.xml.parsers.DocumentBuilderFactory,由 SPI 的实现所提供的。如在 Apache Xerces 中,实现的类是 org.apache.xerces.jaxp.DocumentBuilderFactoryImpl。而问题在于,SPI 的接口是 Java 核心库的一部分,是由引导类加载器来加载的;SPI 实现的 Java 类一般是由系统类加载器来加载的。引导类加载器是无法找到 SPI 的实现类的,因为它只加载 Java 的核心库。它也不能代理给系统类加载器,因为它是系统类加载器的祖先类加载器。也就是说,类加载器的委托机制无法解决这个问题。
线程上下文类加载器正好解决了这个问题。如果不做任何的设置,Java 应用的线程的上下文类加载器默认就是系统上下文类加载器。在 SPI 接口的代码中使用线程上下文类加载器,就可以成功的加载到 SPI 实现的类。线程上下文类加载器在很多 SPI 的实现中都会用到。
java类加载器-系统类加载器的更多相关文章
- JAVA基础知识之JVM-——类加载器
类加载器负责将.class文件加载到内存,并为其创建java.lang.Class对象,这个对象就代表这个类. 在Java中,通过包名+类名来唯一标识一个类,而在JVM中,要用 类加载器实例+包名+类 ...
- Java虚拟机10:类加载器
类与类加载器 虚拟机设计团队把类加载阶段张的"通过一个类的全限定名来获取此类的二进制字节流"这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这 ...
- java类加载器-Tomcat类加载器
在上文中,已经介绍了系统类加载器以及类加载器的相关机制,还自定制类加载器的方式.接下来就以tomcat6为例看看tomat是如何使用自定制类加载器的.(本介绍是基于tomcat6.0.41,不同版本可 ...
- Java魔法堂:类加载器入了个门
一.前言 <Java魔法堂:类加载机制入了个门>中提及整个类加载流程中只有加载阶段作为码农的我们可以入手干预,其余均由JVM处理.本文将记录加载阶段的核心组件——类加载器的相关信息,以便日 ...
- 深入剖析Classloader(二)--根类加载器,扩展类加载器与系统类加载器
原文地址:http://yhjhappy234.blog.163.com/blog/static/31632832201152555245584/?suggestedreading&wumii ...
- JAVA提高七:类加载器
今天我们学习类加载器,关于类加载器其实和JVM有很大关系,在这里这篇文章只是简单的介绍下类加载器,后面学习到JVM的时候还会详细讲到类加载器,本文分为下面几个小节讲解: 一.认识类加载器 1.什么是类 ...
- Java虚拟机14:类加载器
类与类加载器 虚拟机设计团队把类加载阶段张的"通过一个类的全限定名来获取此类的二进制字节流"这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这 ...
- Java面试题之类加载器有哪些?什么是双亲委派模型
类加载器有哪些: 1.启动类加载器(Bootstrap ClassLoader):这个类加载器负责将存放在<JAVA_HOME>\lib目录中的,或被-Xbootclasspath参数所指 ...
- java类加载器-----用户自定义类加载器实现
java类加载器主要分为如下几种: jvm提供的类加载器 根类加载器:底层实现,主要加载java核心类库(如:java.lang.*) 扩展类加载器:使用java代码实现,主要加载如:jre/lib/ ...
随机推荐
- 高亮 TRichEdit 当前行
var gStart, gLength, gCol: Integer; procedure SetRichEdit(aRichEdit: TRichEdit); var fRow, fCol: ...
- pthread——pthread_cleanup
Pthread_cleanup用于注册线程清理函数,注册的清理函数将在线程被取消或者主动调用pthread_exit时被调用: 一个简单的示例: #include <pthread.h& ...
- C++11新特性总结 (一)
1. 概述 最近在看C++ Primer5 刚好看到一半,总结一下C++11里面确实加了很多新东西,如果没有任何了解,别说自己写了,看别人写的代码估计都会有些吃力.C++ Primer5是学习C++1 ...
- vc编译 zlib 1.2.8
最近用到gzip关的算法,于是想起了zlib这个库,于是将其下载下来编译. 首先,在官网上下载源码包:http://zlib.net/zlib-1.2.8.tar.gz 解压之后,打开vc 命令工具: ...
- Android setTag方法的key问题
android在设计View类时,为了能储存一些辅助信息,设计一个一个setTag/getTag的方法.这让我想起在Winform设计中每个Control同样存在一个Tag. 今天要说的是我最近学习a ...
- 4、CC2541芯片中级教程-OSAL操作系统(简单AT指令实现+IIC软件和硬件实现驱动MPU6050)
本文根据一周CC2541笔记汇总得来—— 适合概览和知识快速索引—— 全部链接: 中级教程-OSAL操作系统\OSAL操作系统-实验01 OSAL初探 [插入]SourceInsight-工程建立方法 ...
- 3、CC2541芯片中级教程-OSAL操作系统(ADC光敏电阻和修改串口波特率)
本文根据一周CC2541笔记汇总得来—— 适合概览和知识快速索引—— 全部链接: 中级教程-OSAL操作系统\OSAL操作系统-实验01 OSAL初探 [插入]SourceInsight-工程建立方法 ...
- [ACM_几何] The Deadly Olympic Returns!!! (空间相对运动之最短距离)
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28235#problem/B 题目大意: 有两个同时再空间中匀速运动的导弹,告诉一个时间以 ...
- redis系列-redis的连接
Redis 是完全开源免费的,遵守BSD协议,先进的key - value持久化产品.它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Map), 列表(list ...
- Atitit 如何让精灵控件运动
Atitit 如何让精灵控件运动 ##让Sushi精灵动起来 上面的代码,我们创建了静态的sushiSprite,现在我们让它动起来.使它从屏幕顶部下落到屏幕底部.在addSushi方法中添加如下代 ...