系统类加载器

系统类加载器可能都耳详能熟,但是为了完整点,还是先简单的说说系统的类加载器吧。

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类加载器-系统类加载器的更多相关文章

  1. JAVA基础知识之JVM-——类加载器

    类加载器负责将.class文件加载到内存,并为其创建java.lang.Class对象,这个对象就代表这个类. 在Java中,通过包名+类名来唯一标识一个类,而在JVM中,要用 类加载器实例+包名+类 ...

  2. Java虚拟机10:类加载器

    类与类加载器 虚拟机设计团队把类加载阶段张的"通过一个类的全限定名来获取此类的二进制字节流"这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这 ...

  3. java类加载器-Tomcat类加载器

    在上文中,已经介绍了系统类加载器以及类加载器的相关机制,还自定制类加载器的方式.接下来就以tomcat6为例看看tomat是如何使用自定制类加载器的.(本介绍是基于tomcat6.0.41,不同版本可 ...

  4. Java魔法堂:类加载器入了个门

    一.前言 <Java魔法堂:类加载机制入了个门>中提及整个类加载流程中只有加载阶段作为码农的我们可以入手干预,其余均由JVM处理.本文将记录加载阶段的核心组件——类加载器的相关信息,以便日 ...

  5. 深入剖析Classloader(二)--根类加载器,扩展类加载器与系统类加载器

    原文地址:http://yhjhappy234.blog.163.com/blog/static/31632832201152555245584/?suggestedreading&wumii ...

  6. JAVA提高七:类加载器

    今天我们学习类加载器,关于类加载器其实和JVM有很大关系,在这里这篇文章只是简单的介绍下类加载器,后面学习到JVM的时候还会详细讲到类加载器,本文分为下面几个小节讲解: 一.认识类加载器 1.什么是类 ...

  7. Java虚拟机14:类加载器

    类与类加载器 虚拟机设计团队把类加载阶段张的"通过一个类的全限定名来获取此类的二进制字节流"这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这 ...

  8. Java面试题之类加载器有哪些?什么是双亲委派模型

    类加载器有哪些: 1.启动类加载器(Bootstrap ClassLoader):这个类加载器负责将存放在<JAVA_HOME>\lib目录中的,或被-Xbootclasspath参数所指 ...

  9. java类加载器-----用户自定义类加载器实现

    java类加载器主要分为如下几种: jvm提供的类加载器 根类加载器:底层实现,主要加载java核心类库(如:java.lang.*) 扩展类加载器:使用java代码实现,主要加载如:jre/lib/ ...

随机推荐

  1. Win10 设置外网多用户远程桌面连接

    主要原理:利用路由器的虚拟服务器功能,将内网的Ip地址通过端口映射提供给外网,使得外网能够访问到目的主机. 1. 配置路由器上的虚拟服务器,假设目的主机内网的ip为192.168.1.100,则配置如 ...

  2. Ubuntu16.04使用阿里云镜像安装Mongodb

    一.概述 近日要在新的Ubuntu16.04系统上安装MongoDB,某度结果后直接从Mongo官网直接获得3.2版本的下载链接,结果在下载时发觉速度慢的可怜.迫于无奈,只能找国内的镜像下载.切换国内 ...

  3. 调试SQLSERVER (一)生成dump文件的方法

    调试SQLSERVER (一)生成dump文件的方法 调试SQLSERVER (二)使用Windbg调试SQLSERVER的环境设置调试SQLSERVER (三)使用Windbg调试SQLSERVER ...

  4. ng2-timesheet, 一个timesheet.js的angular2复制版

    一个 timesheet.js (JavaScript library for HTML5 & CSS3 time sheets) 的 Angular 2 复制版 用法: npm instal ...

  5. Android度量单位说明(DIP,DP,PX,SP) (转帖)

    (一)概念 dip: device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA.HVGA和QVGA 推荐使用这个,不 ...

  6. 作业三 代码规范 代码复审 PSP

    1.是否需要有代码规范(5分) 对于是否需要有代码规范,请考虑下列论点并反驳/支持: 1这些规范都是官僚制度下产生的浪费大家的编程时间.影响人们开发效率, 浪费时间的东西. 反对.我并不认为代码规范都 ...

  7. Python2.6下基于rsa的加密解密

    生成公钥的私钥: # -*- coding: UTF-8 -*- import rsa import base64 (public_key, private_key) = rsa.newkeys(10 ...

  8. merge sort and quick sort 自己去理解吧

    <?php $digits=array(,,,,,,,); function quickSort($arr){ $len=count($arr); ){ return $arr; } $midK ...

  9. Linux 文件描述符和重定向

    200 ? "200px" : this.width)!important;} --> 介绍 文件描述符是与文件输入.输出相关联的整数,在编写脚本时会经常使用标准的文件描述符 ...

  10. C#Lite Unity热更新开源解决方案改名C#Light

    因为此脚本语言与C#Lite Framework 开源项目重名,故修改名称,发音不变.