六、ClassLoader源码分析及线程上下文相关

获取系统类加载器源码分析

ClassLoader.getSystemClassLoader();    //获取系统类加载器

首先可以看下该方法的doc文档,如下:

Returns the system class loader for delegation. This is the default delegation parent for new ClassLoader instances, and is typically the class loader used to start the application.

This method is first invoked early in the runtime's startup sequence, at which point it creates the system class loader and sets it as the context class loader of the invoking Thread.

The default system class loader is an implementation-dependent instance of this class.

If the system property "java.system.class.loader" is defined when this method is first invoked then the value of that property is taken to be the name of a class that will be returned as the system class loader. The class is loaded using the default system class loader and must define a public constructor that takes a single parameter of type ClassLoader which is used as the delegation parent. An instance is then created using this constructor with the default system class loader as the parameter. The resulting class loader is defined to be the system class loader.

该段话的含义主要说明该方法返回的类加载器是作为系统类加载器,用来初始化加载应用的,并且会将调调用该方法的线程上下文的类加载器设置为该类加载器。如果设置了 java.system.class 那么就可以修改系统类加载器,但是必须定义一个公共构造函数,该构造函数接受类装入器类型的单个参数,该参数用作委托父类,其父类就是系统类加载器,该构造方法是由jvm调用的。


进入initSystemClassLoader方法查看


sclSet:  判断系统类加载器是否加载,如果已经加载就为true,反之则为false

scl:        表示系统类加载器


构建Launcher对象,因为Launcher不是开源的此处的代码为反编译后的效果,从其逻辑中可以看到,主要完成三件事:

1:获取扩展类加载器

2:获取系统类加载器,并且将扩展类加载器作为父加载器传递给系统类加载器

3:设置线程上文件类加载器为系统类加载器


根据此处描述可以发现,扩展类加载器是从 System.getProperty("java.ext.dirs") 结果中中加载的,

同理系统类加载器的代码如下:


系统类加载器是从 System.getProperty("java.class.path") 的结果中的目录加载的。


最终会调用 SystemClassLoaderAction的run方法


此处代码先判断 System.getProperty("java.system.class.loader") 是否有值,如果没有值表示系统类加载器就是为 AppClassLoader,否则表示应用指定了系统类加载器

此处主要完成 用户自定义类加载器的实列化并且将AppClassLoader作为父加载器传入构造方法中,最终构建出一个新的用户自定义的系统类加载器,最终将该类加载器设置为当前线程的类加载器。

线程上下文类加载器作用

当前类加载器(Current ClassLoader)

每个类都会使用自己的类加载器(即加载自身的类加载器)去加载器其他的类(指的是所依赖的类),如ClassX引用了ClassY,那么ClassX的类加载器就会去加载ClassY(

前提是ClassY尚未被加载)

线程上下文类加载器(Context ClassLoader)

线程上下文类加载器是从JDK1.2开始引入的,类Thread中的getContextClassLoader()与setContextClassLoader(ClassLoader cl)分别用来获取和设置上下文类加载器。

如果没有通过setContextClassLoader(ClassLoader cl)进行设置的话,线程将继承父线程的上下文类加载器。java应用运行时的初始线程上下文类加载器是系统类加载器。

在线程中运行的代码可以通过该类加载器加载类与资源。

线程上下文类加载器的重要性:

SPI(Service Provider Interface)

父ClassLoader可以使用当前线程Thread.currentThread().getContextClassLoader()所指定的classLoader加载类,这就改变了父ClassLoader不能使用子ClassLoader或者

其他没有直接父子关系的ClassLoader加载类的情况,即改变了双亲委派模型。

线程上下文类加载器就是当前线程的Current ClassLoader。

在双亲委派模型线下,类加载器是由下至上的,即下层的类加载器会委托上层进行加载。但是对于SPI来说,有些接口是Java核心库所提供的,而Java核心库是由启动类加载器

来加载的,而这些接口的实现却来自不同的jar包(厂商提供),java的启动类加载器不会加载其他来源的jar包,这样传统的双亲委托模型就无法满足SPI的要求。而通过给定

线程上下文类加载器就可以通过线程上下文类加载器来完成对于接口实现类的加载。

线程上下文类加载器的一般使用规则


线程上下文类加载器的一般使用(获取 - 使用 - 还原)

//获取原始线程类加载器

ClassLoader classLoader=Thread.currentThread().getContextClassLoader();

try{

//获取需要使用的类加载器

ClassLoader targetLoader=getClassLoader();

//使用获取的类加载

Thread.currentThread.setContetClassLoader(targetLoader);

method();

}finally{

//还原原始的线程类加载器

Thread.currentThread.setContetClassLoader(classLoader);

}

method里面调用了Thread.currentThread().getContextClassLoader()获取当前上下文来加载器做某些事情。

如果一个类是由A加载的,那么这个类依赖的类也是由相同的类加载器加载的(前提是该类没有被加载过)

ContextClassLoader的作用就是为了破坏java类的加载委托机制。

当高层提供了统一的接口让低层去实现,同事又要在高层加载(或实列化)低层的类时,就必须要通过线程上下文类加载器来帮助高层的ClassLoader找到并加载该类。


加载Test5的类加载器为AppClassLoader,其线程类上下文加载器也为AppClassLoader,其父类加载器为扩展类加载器

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容

  • ClassLoader翻译过来就是类加载器,普通的java开发者其实用到的不多,但对于某些框架开发者来说却非常常见...
    时待吾阅读 1,076评论 0 1
  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,812评论 0 38
  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi阅读 7,334评论 0 10
  • pyspark.sql模块 模块上下文 Spark SQL和DataFrames的重要类: pyspark.sql...
    mpro阅读 9,457评论 0 13
  • 你没来晚,戳蓝字一键关注楼上小花 每晚21:21,我有故事和你分享 文 | 花姐 图 | 网络 01 周五晚上我...
    楼上小花阅读 506评论 0 0