文档章节

ClassLoader的工作原理

t
 tujie
发布于 2016/04/13 10:34
字数 1704
阅读 13
收藏 0
点赞 1
评论 0

每个运行中的线程都有一个成员contextClassLoader,用来在运行时动态地载入其它类 
系统默认的contextClassLoader是systemClassLoader,所以一般而言java程序在执行时可以使用JVM自带的类、$JAVA_HOME/jre/lib/ext/中的类和$CLASSPATH/中的类 
可以使用Thread.currentThread().setContextClassLoader(...);更改当前线程的contextClassLoader,来改变其载入类的行为 

ClassLoader被组织成树形,一般的工作原理是: 
1) 线程需要用到某个类,于是contextClassLoader被请求来载入该类 
2) contextClassLoader请求它的父ClassLoader来完成该载入请求 
3) 如果父ClassLoader无法载入类,则contextClassLoader试图自己来载入 


Java中一共有四个类加载器,之所以叫类加载器,是程序要用到某个类的时候,要用类加载器载入内存。 
    这四个类加载器分别为:Bootstrap ClassLoader、Extension ClassLoader、AppClassLoader 
和URLClassLoader,他们的作用其实从名字就可以大概推测出来了。其中AppClassLoader在很多地方被叫做System ClassLoader 

Bootstrap ClassLoader是在JVM开始运行的时候加载java的核心类,是用C++编写的,它用来加载核心类库,在JVM源代码中这样写道: 
static const char classpathFormat[] = 
"%/lib/rt.jar:" 
"%/lib/i18n.jar:" 
"%/lib/sunrsasign.jar:" 
"%/lib/jsse.jar:" 
"%/lib/jce.jar:" 
"%/lib/charsets.jar:" 
"%/classes"; 
Extension ClassLoader是用来加载扩展类,即/lib/ext中的类。 
AppClassLoader用来加载Classpath的类,是和我们关系最密切的类。 
URLClassLoader用来加载网络上远程的类 


1. 预先加载与依需求加载 

Java 运行环境为了优化系统,提高程序的执行速度,在 JRE 运行的开始会将 Java 运行所需要的基本类采用预先加载( pre-loading )的方法全部加载要内存当中,因为这些单元在 Java 程序运行的过程当中经常要使用的,主要包括 JRE 的 rt.jar 文件里面所有的 .class 文件。 

当 java.exe 虚拟机开始运行以后,它会找到安装在机器上的 JRE 环境,然后把控制权交给 JRE , JRE 的类加载器会将 lib 目录下的 rt.jar 基础类别文件库加载进内存,这些文件是 Java 程序执行所必须的,所以系统在开始就将这些文件加载,避免以后的多次 IO 操作,从而提高程序执行效率。 

相对于预先加载,我们在程序中需要使用自己定义的类的时候就要使用依需求加载方法( load-on-demand ),就是在 Java 程序需要用到的时候再加载,以减少内存的消耗,因为 Java 语言的设计初衷就是面向嵌入式领域的。

2. 隐式加载和显示加载 

Java 的加载方式分为隐式加载( implicit )和显示加载( explicit ),上面的例子中就是用的隐式加载的方式。所谓隐式加载就是我们在程序中用 new 关键字来定义一个实例变量, JRE 在执行到 new 关键字的时候就会把对应的实例类加载进入内存。隐式加载的方法很常见,用的也很多, JRE 系统在后台自动的帮助用户加载,减少了用户的工作量,也增加了系统的安全性和程序的可读性。 

Java代码  收藏代码

  1. Class c = Class.forName("TestClass");   

  2.   

  3.  TestClass object = (TestClass)c.newInstance();   

  4.   

  5. object.method();   


通过 Class 类的 forName (String s) 方法把自定义类 TestClass 加载进来,并通过 newInstance ()方法把实例初始化。事实上 Class 类还很多的功能,这里就不细讲了。 

Class 的 forName() 方法还有另外一种形式: Class forName(String s, boolean flag, ClassLoader classloader) , s 表示需要加载类的名称, flag 表示在调用该函数加载类的时候是否初始化静态区, classloader 表示加载该类所需的加载器。 

forName (String s) 是默认通过 ClassLoader.getCallerClassLoader() 调用类加载器的,但是该方法是私有方法,我们无法调用,如果我们想使用 Class forName(String s, boolean flag, ClassLoader classloader) 来加载类的话,就必须要指定类加载器,可以通过如下的方式来实现: 

Test test = new Test();//Test 类为自定义的一个测试类; 

ClassLoader cl = test. getClass().getClassLoader(); 

                         // 获取 test 的类装载器; 

Class c = Class.forName("TestClass", true, cl); 

因为一个类要加载就必需要有加载器,这里我们是通过获取加载 Test 类的加载器 cl 当作加载 TestClass 的类加载器来实现加载的。 
3. 自定义类加载机制 

之前我们都是调用系统的类加载器来实现加载的,其实我们是可以自己定义类加载器的。利用 Java 提供的 java.net.URLClassLoader 类就可以实现。下面我们看一段范例: 

    try{ 

               URL url = new URL("file:/d:/test/lib/"); 

               URLClassLoader urlCL = new URLClassLoader(new URL[]{url}); 

               Class c = urlCL.loadClass("TestClassA"); 

               TestClassA object = (TestClassA)c.newInstance(); 

               object.method(); 

        }catch(Exception e){ 

               e.printStackTrace(); 

        } 

我们通过自定义的类加载器实现了 TestClassA 类的加载并调用 method ()方法。分析一下这个程序:首先定义 URL 指定类加载器从何处加载类, URL 可以指向网际网络上的任何位置,也可以指向我们计算机里的文件系统 ( 包含 JAR 文件 ) 。上述范例当中我们从 file:/d:/test/lib/ 处寻找类;然后定义 URLClassLoader 来加载所需的类,最后即可使用该实例了。 

4. 类加载器的阶层体系 

讨论了这么多以后,接下来我们仔细研究一下 Java 的类加载器的工作原理: 

当执行 java ***.class 的时候, java.exe 会帮助我们找到 JRE ,接着找到位于 JRE 内部的 jvm.dll ,这才是真正的 Java 虚拟机器 , 最后加载动态库,激活 Java 虚拟机器。虚拟机器激活以后,会先做一些初始化的动作,比如说读取系统参数等。一旦初始化动作完成之后,就会产生第一个类加载器―― Bootstrap Loader , Bootstrap Loader 是由 C++ 所撰写而成,这个 Bootstrap Loader 所做的初始工作中,除了一些基本的初始化动作之外,最重要的就是加载 Launcher.java 之中的 ExtClassLoader ,并设定其 Parent 为 null ,代表其父加载器为 BootstrapLoader 。然后 Bootstrap Loader 再要求加载 Launcher.java 之中的 AppClassLoader ,并设定其 Parent 为之前产生的 ExtClassLoader 实体。这两个加载器都是以静态类的形式存在的。这里要请大家注意的是, Launcher$ExtClassLoader.class 与 Launcher$AppClassLoader.class 都是由 Bootstrap Loader 所加载,所以 Parent 和由哪个类加载器加载没有关系。 
这三个加载器就构成我们的 Java 类加载体系。他们分别从以下的路径寻找程序所需要的类: 

BootstrapLoader : sun.boot.class.path 

ExtClassLoader:      java.ext.dirs 

AppClassLoader:      java.class.path 

这三个系统参量可以通过 System.getProperty() 函数得到具体对应的路径。 





本文转载自:http://sys53.iteye.com/blog/622626

共有 人打赏支持
t
粉丝 0
博文 10
码字总数 0
作品 0
武汉
仿照Tomcat写自己的classloader

标准JVM的3个classloader以及原理就不多说了. Tomcat自己的classloader是WebAppClassLoader. 每个WEB应用运行与自己的WebAppClassLoader中.在之前,这个classloader和system classloader之间还...

xpbug ⋅ 2013/01/15 ⋅ 1

ClassLoader 原理

ClassLoader的工作原理 每个运行中的线程都有一个成员contextClassLoader,用来在运行时动态地载入其它类 系统默认的contextClassLoader是systemClassLoader,所以一般而言java程序在执行时可...

北京_ ⋅ 2014/08/06 ⋅ 0

Java反射总结

Java 反射总结 类装载器工作机制 类装载器就是寻找类的节码文件并构造出类在JVM 内部表示对象的组件。在Java 中, 类装载器把一个类装入JVM 中,要经过以下步骤: 1.装载:查找和导入Class...

ZooKeeper ⋅ 2013/11/27 ⋅ 2

Android动态加载技术 系列索引

Android Dynamical Loading 大家新年好,最近花了点时间,慢慢把这个系列的内容稍微调整了下。 Last Edit: 2016-2-10 基本信息 Author:Kaedea GitHub:android-dynamical-loading 动态加载介...

Kaede ⋅ 2017/11/29 ⋅ 0

知识总结 插件化学习 Activity加载分析

现在安卓插件化已经很成熟,可以直接用别人开源的框架实现自己项目,但是学习插件化的实现原理是安卓研发工程师加深安卓系统理解的很好途径。 安卓插件化学习 插件Activity加载方式分析 实现...

CankingApp ⋅ 2017/05/19 ⋅ 0

JVM类加载器-源码分析

前言 我们在JVM类加载器-原理一文中了解了JVM类加载器的基本原理。现在我们一起通过ClassLoader类及其相关源码来详细分析、理解JVM类加载器的体系,深入理解JVM类加载器的原理与实现。 Clas...

Justlearn ⋅ 2017/04/30 ⋅ 0

Java基础巩固笔记(3)-类加载器

Contents java基础巩固笔记(3)-类加载器 默认类加载器 类加载器的委托机制 自定义类加载器的编写原理 参考资料 java类加载器就是在运行时在JVM中动态地加载所需的类,java类加载器基于三个机...

卟想苌亣 ⋅ 2017/12/04 ⋅ 0

JVM 类加载器的工作原理

面向对象的原理:认为万事万物都是对象,类也是对象,是class类的对象叫做类类型。 (why)Java类加载器的作用就是在运行时加载类。(How?)Java类加载器基于三个机制:委托、可见性和单一性...

亚特兰缇斯 ⋅ 2015/03/06 ⋅ 0

Java中的类加载器

首先声明,我是因为看了ImportNew网站上的几篇关于类加载器的文章之后,才萌生了写这篇文章的想法。所以在写这篇文章时,参考了该网站上的几篇相关的文章,但是加入了很多自己的理解,绝对不...

java大哥 ⋅ 2017/11/23 ⋅ 0

MultiDex工作原理分析和优化方案

动态加载技术(插件化)系列已经坑了有一段时间了,不过UP主我并没有放弃治疗哈,相信在不就的未来就可以看到“系统Api Hook模式”和插件化框架Frontia的更新了。今天要讲的是动态加载技术的...

Kaede ⋅ 2017/11/29 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JPA入门,配置文件的设置

<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http......

码农屌丝 ⋅ 23分钟前 ⋅ 0

Java基础——面向对象和构造器

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权;凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记。 静态成员介绍 为什么要有静态成员?静态成员用来...

凯哥学堂 ⋅ 25分钟前 ⋅ 0

vmware中Centos 7 linux的LVM磁盘扩容

系统是RHEL7(centos7差不多一样) 关闭系统,在vmware、设置、硬盘、扩展、输入数字大于当前系统内存、点击扩展。 开机再查看磁盘信息 fdisk -l 注意:可以看出sda磁盘增加了,但是根目录还...

gugudu ⋅ 35分钟前 ⋅ 0

JAVA线程sleep和wait方法区别

昨天面试,突然被问到sleep 和 wait的区别,一下子有点蒙,在这里记一下,以示警戒。 首先说sleep,sleep就是正在执行的线程主动让出cpu,cpu去执行其他线程,在sleep指定的时间过去后,cpu...

徐玉强 ⋅ 37分钟前 ⋅ 0

vuex学习--模块

随着项目复杂性增加,共享状态也越来越多。需要对转态操作进行分组,分组后在进行分组编写。学习一下module:状态管理器的模块组操作。 首先是声明: const moduleA={ state,mutations,g...

大美琴 ⋅ 40分钟前 ⋅ 0

Selenium 简单入门

安装 pip install selenium 驱动下载 https://chromedriver.storage.googleapis.com/index.html 下载最新的驱动,放入path中,可以放入Python的scripts目录下,也可以放入Chrome安装目录,并...

阿豪boy ⋅ 41分钟前 ⋅ 0

292. Nim Game - LeetCode

Question 292. Nim Game Solution 思路:试着列举一下,就能发现一个n只要不是4的倍数,就能赢。 n 是否能赢1 true2 true3 true4 false 不论删除几,对方都能一把赢5 t...

yysue ⋅ 今天 ⋅ 0

6.5 zip压缩工具 6.6 tar打包 6.7 打包并压缩

zip压缩工具 zip命令可以压缩目录和文件,-r 压缩目录。 zip使用方法 zip 1.txt.zip 1.txt //压缩文件 zip -r 123.zip 123/ //压缩目录 unzip 1.txt.zip //解压 unzip 123.zip -d /root/456...

Linux_老吴 ⋅ 今天 ⋅ 0

react-loadable使用跳坑

官方给react-loadable的定义是: A higher order component for loading components with dynamic imports. 动态路由示例 withLoadable.js import React from 'react'import Loadable fro......

pengqinmm ⋅ 今天 ⋅ 0

记录工作中遇到的坑

1、ios safari浏览器向下滚动会触发window resize事件

端木遗风 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部