详解JAVA类加载器
创始人
2024-05-29 22:39:49
0

目录

1.概述

2.双亲委派

3.ServiceClassLoader

4.URLClassLoader

5.加载冲突


1.概述

概念:

类加载器(Class Loader)是Java虚拟机(JVM)的一个重要组件,负责加载Java类到内存中并使其可以被JVM执行。类加载器是Java程序的核心机制之一。

分类:

类加载器一共有三种:

  • 启动类加载器,加载系统类rt.jar。
  • 扩展类加载器,加载JDK内部,rt.jar之外,由于JDK版本迭代而新出现的扩展类。
  • 应用类加载器加载J用户所配置的classpath下的类。

三种类加载器之间从上到下有父子关系,上层是下层的父加载器。

2.双亲委派

在类加载中可能会遇见这样一种情况:

JDK里自带一个java.lang.String,有一个恶意的攻击类也将类的全类名命名为java.lang.String。如果我们想使用String类型的时候,类加载器将这个伪装成JDK的String类的恶意类加载执行,系统就将遭受到破坏。

很明显,为了安全起见JDK需要一种合理的加载方式来控制类的加载,这种合理的加载方式就是——双亲委派机制。

双亲委派机制总结起来就是:

先找父级加载器要,要是父级加载器没有,再由自己加载。

因为启动类加载器、扩展类加载器工作在应用的启动阶段,加载的也是JDK内核相关的jar,与应用没有太大关系,与应用相关的只有应用程序加载类,而应用程序的父级最多也就是扩展类加载器、启动类加载器,也就是最多找两个双亲拿,所以称为双亲委派机制。

整个类加载的详细流程为:

我们来看看任意一个ClassLoader的loadClass源码,整个源码中双亲委派的体现很直接:

类加载器在需要加载一个类(class)的时候会先判断类是否被自己加载过,

如果没有,调用其成员变量classloader parent委托其父载器帮忙加载,

父加载器再重复以上过程,如果递归到最顶级的启动类加载器,发现都加载不了,

当前启动器会自行加载。

3.ServiceClassLoader

SPI机制:

SPI(Service Provider Interface),是在JDK1.6中提出的一种基于接口的服务发现机制,它允许第三方服务提供者扩展框架的功能。在SPI机制中,框架定义一组接口,并规定这些接口的实现类必须以一定的命名规则放在特定的路径下,然后通过Java自带的SPI机制,动态地加载和实例化这些实现类。

基于SPI机制可以实现这样的生态结构,由官方制定一些标准,厂商去给出实现,也就是官方给出接口,由各大厂商去实现接口,如JAVA EE规范中的JDBC规范等等,支撑SPI实现的核心是一个类加载器——ServiceClassLoader。

ServiceClassLoader是一种用于加载和实例化服务提供者的工具类。服务提供者是指实现了特定接口或抽象类的类,而服务加载器则负责在运行时动态地查找和加载这些实现类。

  • 定义服务接口:定义一个Java接口或抽象类,用于描述服务提供者必须实现的行为。

  • 实现服务提供者:定义一个或多个服务提供者,实现服务接口或抽象类。

  • 配置服务提供者:在META-INF/services目录下创建一个以服务接口或抽象类名为文件名的文件,并在文件中列出所有实现服务接口或抽象类的类名。

  • 加载服务提供者:使用Service Loader类动态加载和实例化服务提供者。

代码示例:

接口:

package com.eryi;public interface HelloService {void sayHello();
}

实现类:

package com.eryi;public class ChineseHelloService implements HelloService{@Overridepublic void sayHello() {System.out.println("你好!");}
}
package com.eryi;public class EnglishHelloService implements HelloService{@Overridepublic void sayHello() {System.out.println("Hello!");}
}

发布服务:

在META-INF/services目录下创建一个名为"com.eryi.HelloService"的文件,文件内容如下:

com.eryi.EnglishHelloService
com.eryi.ChineseHelloService

服务发现:

package com.eryi;import java.util.ServiceLoader;public class test {public static void main(String[] args) {ServiceLoader loader = ServiceLoader.load(HelloService.class);for (HelloService service : loader) {service.sayHello();}}
}

运行结果:

4.URLClassLoader

启动类加载器、扩展类加载器、应用类加载器均是在程序工作之前完成对各个路径下所有jar包的加载的,这些路径里的jar包后续如果有什么变化,这三个类加载器是无法进行加载从而动态进行更新的。URLClassLoader就是为了实现这种动态加载而出现的。

URLClassLoader支持三种路径:

  • 目录

  • jar包

  • 网络

代码示例:

public class test {public static void main(String[] args) throws Exception {// 创建一个URLClassLoader,指定加载路径为当前目录URLClassLoader classLoader = new URLClassLoader(new URL[] { new URL("file:./") });// 动态加载HelloWorld类Class helloWorldClass = classLoader.loadClass("HelloWorld");// 创建HelloWorld对象Object helloWorld = helloWorldClass.newInstance();// 调用HelloWorld对象的sayHello方法helloWorldClass.getMethod("sayHello").invoke(helloWorld);}
}class HelloWorld {public void sayHello() {System.out.println("Hello, world!");}
}

由于URLClassLoader具有动态加载的特性,所以很适合拿来做热部署。

5.加载冲突

同一个类被不同加载器加载,加载结果视为两个不同类。

所以在加载之前需要判断是否被加载,如果未加载,则遵循双亲委托模型,从而避免加载冲突。

代码示例:

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;public class Main {public static void main(String[] args) throws Exception {// 创建两个不同的URLClassLoader,分别加载同一个类URL[] classpath = { new File("classes/").toURI().toURL() };URLClassLoader classLoader1 = new URLClassLoader(classpath);URLClassLoader classLoader2 = new URLClassLoader(classpath);// 使用classLoader1加载HelloWorld类Class helloWorldClass1 = classLoader1.loadClass("HelloWorld");// 使用classLoader2加载HelloWorld类Class helloWorldClass2 = classLoader2.loadClass("HelloWorld");// 输出两个类是否相同System.out.println(helloWorldClass1 == helloWorldClass2); // false}
}class HelloWorld {public void sayHello() {System.out.println("Hello, world!");}
}

相关内容

热门资讯

安卓系统用的华为应用,探索智能... 你知道吗?在安卓系统里,华为的应用可是个宝库呢!它们不仅功能强大,而且使用起来超级方便。今天,就让我...
安卓变ios系统魅蓝 你知道吗?最近有个朋友突然告诉我,他要把自己的安卓手机换成iOS系统,而且还是魅蓝品牌的!这可真是让...
幻书启世录安卓系统,安卓世界中... 亲爱的读者们,你是否曾在某个夜晚,被一本神奇的书所吸引,仿佛它拥有着穿越时空的力量?今天,我要带你走...
电脑安装安卓系统进不去,安卓系... 电脑安装安卓系统后竟然进不去,这可真是让人头疼的问题啊!你是不是也遇到了这种情况,心里直呼“怎么办怎...
用键盘切换控制安卓系统,畅享安... 你有没有想过,用键盘来控制你的安卓手机?是的,你没听错,就是那个我们每天敲敲打打的小玩意儿——键盘。...
小米安卓镜像系统在哪,小米安卓... 你有没有想过,你的小米手机里有一个隐藏的宝藏——安卓镜像系统?没错,就是那个可以让你的手机瞬间变身成...
安卓手机下载排班系统,高效排班... 你有没有想过,每天忙碌的工作中,有没有什么好帮手能帮你轻松管理时间呢?今天,就让我来给你介绍一个超级...
桌面组件如何弄安卓系统,桌面组... 亲爱的桌面爱好者们,你是否曾梦想过将安卓系统搬到你的电脑桌面上?想象那些流畅的动画、丰富的应用,还有...
安卓13系统介绍视频,新功能与... 亲爱的读者们,你是否对安卓13系统充满好奇?想要一探究竟,却又苦于没有足够的时间去研究?别担心,今天...
车机安卓7.1系统,功能升级与... 你有没有发现,现在的车机系统越来越智能了?尤其是那些搭载了安卓7.1系统的车机,简直就像是个贴心的智...
安卓系统下如何读pdf,And... 你有没有遇到过这种情况:手机里存了一大堆PDF文件,可是怎么也找不到一个能顺畅阅读的工具?别急,今天...
安卓系统全国通用的吗,畅享智能... 你有没有想过,为什么你的手机里装的是安卓系统呢?安卓系统,这个名字听起来是不是有点神秘?今天,就让我...
假苹果手机8安卓系统,颠覆传统... 你有没有想过,如果苹果手机突然变成了安卓系统,会是怎样的景象呢?想象那熟悉的苹果外观,却运行着安卓的...
安卓12.0系统vivo有吗,... 你有没有听说最近安卓系统又升级啦?没错,就是那个让手机焕然一新的安卓12.0系统!那么,咱们国内的手...
核心芯片和安卓系统,探索核心芯... 你知道吗?在科技的世界里,有一对“黄金搭档”正悄悄改变着我们的生活。他们就是——核心芯片和安卓系统。...
如何调安卓系统屏幕颜色,安卓系... 亲爱的手机控们,你是否曾觉得安卓系统的屏幕颜色不够个性,或者是因为长时间盯着屏幕而感到眼睛疲劳?别担...
旧台式电脑安装安卓系统,轻松安... 你那台旧台式电脑是不是已经服役多年,性能逐渐力不从心,却又不忍心让它退役呢?别急,今天就来教你怎么给...
美国要求关闭安卓系统,科技霸权... 美国要求关闭安卓系统:一场技术革新还是政治博弈?在数字化时代,智能手机已经成为我们生活中不可或缺的一...
安卓系统日记本 你有没有发现,手机里的安卓系统日记本,简直就是记录生活点滴的宝藏库呢?想象每天忙碌的生活中,有没有那...
安卓手机广告最少的系统,探索安... 你有没有发现,用安卓手机的时候,广告总是无处不在,让人烦得要命?不过别急,今天我要给你揭秘一个秘密—...