Java
中的所有类,必须被装载到jvm
中才能运行,这个装载工作是由jvm
中的类装载器完成的。JVM
在加载类的时候,都是通过ClassLoader
的loadClass()
方法来加载class的。public class TestClassLoader { public static void main(String[] args) { System.out.println(TestClassLoader.class.getClassLoader()); } }运行结果:
sun.misc.Launcher$AppClassLoader@4e0e2f2a
一、java ClassLoader体系
Java默认是有三个ClassLoader,按层次关系从上到下依次是:
- Bootstrap ClassLoader
- ExtClassLoader
- AppClassLoader
Bootstrap ClassLoader是最顶层的ClassLoader,比较特殊,是用C++编写集成在JVM中的,是JVM启动的时候用来加载一些核心类的,
比如:
rt.jar
,resources.jar
,charsets.jar
,jce.jar
等
import java.net.URL; public class TestClassLoader { public static void main(String[] args) { URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs(); for (int i = 0; i < urls.length; i++) { System.out.println(urls[i].toExternalForm()); } } }
运行结果为:
file:/C:/Program%20Files/Java/jre1.8.0_73/lib/resources.jar file:/C:/Program%20Files/Java/jre1.8.0_73/lib/rt.jar file:/C:/Program%20Files/Java/jre1.8.0_73/lib/sunrsasign.jar file:/C:/Program%20Files/Java/jre1.8.0_73/lib/jsse.jar file:/C:/Program%20Files/Java/jre1.8.0_73/lib/jce.jar file:/C:/Program%20Files/Java/jre1.8.0_73/lib/charsets.jar file:/C:/Program%20Files/Java/jre1.8.0_73/lib/jfr.jar file:/C:/Program%20Files/Java/jre1.8.0_73/classes
Bootstrap ClassLoader加载的类全都是java自有的核心类。
ExtClassLoader、AppClassLoader都是继承自Bootstrap ClassLoader。
ExtClassLoader是用来加载扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目录下的所有的jar
AppClassLoader叫做系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件,包括我们平时运行jar包指定cp参数下的jar包
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { //如果父加载器不为空,使用父加载器加载class if (parent != null) { c = parent.loadClass(name, false); } else { //如果父加载器也为空,使用bootstarpClassLoader加载 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); //如果还为空,调用自定义的加载方法 c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }
这时问题是,parent是什么?
public abstract class ClassLoader { // The parent class loader for delegation private final ClassLoader parent; ... }
原来ClassLoader内部使用了父加载器,这就是双亲委托模式。
如图所示:
当前类加载器先不加载class,委托给父加载器加载class,如果父加载器没有加载成功,本类加载器再加载class。
可以使用下面代码测试下:
public class TestClassLoader { public static void main(String[] args) { ClassLoader loader = MyAppClassLoader.class.getClassLoader(); while(loader != null) { System.out.println(loader); loader = loader.getParent(); } System.out.println(loader); } }
运行结果为:
sun.misc.Launcher$AppClassLoader@4e0e2f2a sun.misc.Launcher$ExtClassLoader@2a139a55 null
java.lang.ClassCaseException
public class MyAppClassLoader extends ClassLoader{ @Override public Class<?> findClass(String name) throws ClassNotFoundException { //从特殊路径下读取class,或者从网络中读取class,不管咋样,实现自己的方法,返回加载class //... } }
四、ContextLoader当前classLoader
首先关于类的加载补充一点就是如果类A是被一个加载器加载的,那么类A中引用的B也是由这个加载器加载的(如果B还没有被加载的话),通常情况下就是类B必须在类A的classpath下。
那么问题来了。某些时候这种顺序机制会造成困扰,特别是jvm需要动态载入有开发者提供的资源时。Java中有一个SPI(Service Provider Interface)标准,使用了SPI的库,比如JNDI,JDBC,等等。
这里以JNDI为例,JNDI的类是由bootstarp ClassLoader从rt.jar中间载入的,但是JNDI具体的核心驱动是由正式的实现提供的,并且通常会处于-cp参数之下(注:也就是默认的System ClassLoader管理),这就要求bootstartp ClassLoader去载入只有SystemClassLoader可见的类,正常的逻辑就没办法处理。怎么办呢?
这时JAVA引入了线程上下文类加载的概 念,线程类加载器默认会从父线程继承,如果没有指定的话,默认就是系统类加载器(AppClassLoader),这样的话当加载第三方驱动的时候,就可 以通过线程的上下文类加载器来加载。
Thread两个方法:
public ClassLoader getContextClassLoader() ;
public void setContextClassLoader(ClassLoader cl) ;
我们在加载动态类的时候,可以是在当前上下文环境下的特定的ClassLoader,然后通过当前上下文的ClassLoader去加载动态类,这样就可以摆脱双亲委托模式了。
如果没有通过 setContextClassLoader(ClassLoader cl)
方法进行设置的话,线程将继承其父线程的上下文类加载器。
相关推荐
【图解版】深入分析ClassLoader类加载工作机制,从原理到JVM的装载过程,详情分析了ClassLoader加载类以及自定义类加载器的过程,不可用于商业用途,如有版权问题,请联系删除!
一、什么是ClassLoader? 大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程序的一个入口函数来调用系统的...
ClassLoader加密技术改进研究,徐首泽,金瓯,ClassLoader加密技术是Java当中用的比较广泛的代码保护技术,本文分析了ClassLoader加密技术的原理,发现并分析了现有方法存在的漏洞,同�
详细介绍ClassLoader的原理和应用。分析2个案例,说明ClassLoader的使用。 第七课 性能监控工具 线程死锁分析 OOM分析 介绍常用的JVM诊断和分析工具,并以死锁和OOM为例,展示这些工具的使用。 第八课 分析Java...
HashMap源码分析与实现、JVM底层奥秘ClassLoader源码分析与案例讲解、大型网站数据库瓶颈之数据库分库分表方案实践、Spring Cloud Eureka场景分析与实战、分库分表之后分布式下如何保证ID全局唯一性、RPC底层通讯...
类的动态装载机制是JVM的一...本文介绍了JVM中类装载的原理、实现以及应用,尤其分析了ClassLoader的结构、用途以及如何利用自定义 的ClassLoader装载并执行Java类,希望能使读者对JVM中的类装载有一个比较深入的理解。
其次深入介绍Java技术,包括I/O技术、中文编码问题、Javac编译原理、class文件结构解析、ClassLoader工作机制及JVM的内存管理等。最后介绍Java服务端技术,主要包括Servlet、Session与Cookie、Tomcat与Jetty服务器、...
通过Classloader可以findClass我们Dex中的方法,由此可以看出,Classloader跟我们Dex是存在某种关系的。我们看一下PathClassloader是如何对Dex文件进行加载的。 源码:dalvik.system.PathClassLoader
而程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,通过Java的类加载机制(ClassLoader)来动态加载某个class文件到内存当中的,从而只有class文件被载入到了内存之后,才能被...
其次深入介绍了Java 技术,包括I/O 技术、中文编码问题、Javac 编译原理、class 文件结构解析、ClassLoader 工作机制及JVM 的内存管理等。最后介绍了Java 服务端技术,主要包括Servlet、Session 与Cookie、Tomcat 与...
Quartz应用与集群原理分析 ] () [ heavyz的Tomcat学习笔记(包括启动流程分析、启动脚本分析) ] () [ java8 新特性讲解系列文章 ] () [ Java 从Jar文件中动态加载类 ] () [ Java并发源码分析 - ThreadPoolExecutor ] ...
其次深入介绍了Java 技术,包括I/O 技术、中文编码问题、Javac 编译原理、class 文件结构解析、ClassLoader 工作机制及JVM 的内存管理等。最后介绍了Java 服务端技术,主要包括Servlet、Session 与Cookie、Tomcat 与...
而程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,通过Java的类加载机制(ClassLoader)来动态加载某个class文件到内存当中的,从而只有class文件被载入到了内存之后,才能被...
├─面试必问-webservice原理分析 │ webservice原理分析.mp4 │ ├─面试必问-使用Springboot快速搭建SSM框架 │ 使用SpringBoot快速搭建SSM框架.mp4 │ ├─面试必问-双十一系统架构之Mysql索引技术剖析 │ 双...
它提供了许多强大的命令行工具,可以帮助开发人员实时监控应用程序的运行状态,以及分析和调试 Java 应用程序的性能问题。 下面我们来介绍 Arthas 的基本原理和一些常用命令。 Arthas 的基本原理是使用 Java Agent ...
第12章 理解ClassLoader chapter_13 第13章 热修复原理 chapter_14 第14章 Hook技术 chapter_15 第15章 插件化技术 本书内容 本书共分为17章,各章内容如下: 第1章介绍Android系统架构、系统源码目录和...
从Instant Run 发布就已经有文章做了详细的介绍,但主要分为两类:一类是讲其主要实现原理或是讲 Instant Run2.0中的 Application 和 ClassLoader 的替换,另一类就是两者结合。但是在Instant Run2.0 以后包括(2.3...
类装载器(ClassLoader)(用来装载.class文件) 执行引擎(执行字节码,或者执行本地方法) 运行时数据区(方法区、堆、java栈、PC寄存器、本地方法栈) 说到GC,记住两点:1、GC是负责回收所有无任何引用对象的...