Java类加载机制及违背分析

  • Java类加载机制
  • tomcat类加载机制
  • 上下文类加载器
  • 类加载器选择

Java类加载 https://blog.csdn.net/cnahyz/article/details/82219210
tomcat类加载 https://www.cnblogs.com/aspirant/p/8991830.html
上下文类加载器 https://blog.csdn.net/zhoudaxia/article/details/35897057

1、Java类加载机制

  • 类加载过程
    类主要的 生命周期有:
    在这里插入图片描述
    加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序进行,而解析阶段则不一定,它在某些情况下可能在初始化阶段后在开始,因为java支持运行时绑定。
    具体的加载过程可以参考:https://blog.csdn.net/zhaocuit/article/details/93038538

  • 类加载器

在这里插入图片描述

BootStrap ClassLoader: 非Java语言实现
        一般由C++语言实现、负责加载java基本类主要是<JAVA_HOME>/lib/rt.jar

Extension ClassLoader: ExtClassLoader
        负责加载java的一些扩展类主要是<JAVA_HOME>/lib/ext目录下的java包
sun.misc.Launcher$ExtClassLoader

static class ExtClassLoader extends URLClassLoader {

Application ClassLoaderAppClassLoader
        负责加载自己定义的类以及第三方框架的类库 也叫系统类加载器 System ClassLoader

static class AppClassLoader extends URLClassLoader {

父子委派关系:加载的时候首先交给父加载器[们]加载,所有为null才自己加载会出现对应的class对象调用getClassLoader返回的可能不是调用 loadClass("classname")的类加载器

双亲委派模型(一般)
        双亲委派模式要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器,请注意双亲委派模式中的父子关系并非通常所说的类继承关系,而是采用组合关系来复用父类加载器的相关代码。
         判断是否加载,若是加载了直接返回,否则交给父类,成功返回,不成功再自己尝试加载
         优势:避免重复加载,防止核心API库被随意篡改。核心包访问权限,否则抛出异常: java.lang.SecurityException: Prohibited package name: java.lang

例外(违反双亲委派)

  • 自定义加载顺序,但以java开头的类不能被自定义的了加载器加载,这是由java安全机制保证的,避免混乱
  • 网状加载顺序:OSGI和java9模块化系统中,一个模块加载的类可能是自己加载也可能是委派给其他类加载器
  • 父加载器委派给子加载器:线程上下文类加载器

2、tomcat类加载机制

        Tomcat的类加载机制违反了双亲委托原则的,对于一些未加载的非基础类(Object,String等),各个web应用自己的类加载器(WebAppClassLoader)会优先加载,加载不到时再交给commonClassLoader走双亲委托。

对于JVM来说:因此,按照这个过程可以想到,如果同样在CLASSPATH指定的目录中和自己工作目录中存放相同的class,会优先加载CLASSPATH目录中的文件。

在这里插入图片描述
实际类继承关系UML类图:
在这里插入图片描述

3、上下文类加载器

        线程上下文类加载器(context class loader)是从 JDK 1.2 开始引入的。类 java.lang.Thread中的方法 getContextClassLoader()setContextClassLoader(ClassLoader cl)用来获取和设置线程的上下文类加载器。如果没有通过 setContextClassLoader(ClassLoader cl)方法进行设置的话,线程将继承其父线程的上下文类加载器。Java 应用运行的初始线程的上下文类加载器是系统类加载器。在线程中运行的代码可以通过此类加载器来加载类和资源。

解决:Java 提供了很多服务提供者接口(Service Provider Interface,SPI)(Service Provider Interface,SPI)第三方API,SPI 实现的 Java 类一般是由系统类加载器来加载的。启动类加载器是无法找到 SPI 的实现类的,因为它只加载 Java 的核心库。它也不能代理给系统类加载器,因为它是系统类加载器的祖先类加载器。也就是说,类加载器的代理模式无法解决这个问题。
        此时Java提供了线程上下文类加载器,用来打破原有的双亲委派机制,让父加载器(启动类加载器)可以代理给子加载器(系统类加载器)让其加载,即不走双亲委派,子加载器先加载。

4、类加载器选择

一般有:系统类加载器、当前类加载器、上下文加载器
1、系统类加载器 通常不会使用。此类加载器处理启动应用程序时classpath指定的类,可以通过ClassLoader.getSystemClassLoader()来获得。所有的ClassLoader.getSystemXXX()接口也是通过这个类加载器加载的。一般不要显式调用这些方法,应该让其他类加载器代理到系统类加载器上。
2、一般来说,上下文类加载器要比当前类加载器更适合于框架编程,而当前类加载器则更适合于业务逻辑编程。

Java的使用:

        (1)JNDI使用线程上下文类加载器。

        (2)Class.getResource()和Class.forName()使用当前类加载器。

        (3)JAXP使用上下文类加载器。

        (4)java.util.ResourceBundle使用调用者的当前类加载器。

        (5)URL协议处理器使用java.protocol.handler.pkgs系统属性并只使用系统类加载器。

        (6)Java序列化API缺省使用调用者当前的类加载器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值