Class类加载过程

本文详细介绍了Java命令执行代码流程,重点解析了类加载器的工作原理,包括类加载的步骤、各种类加载器的角色,特别是双亲委派机制及其背后的考量。同时探讨了为何及如何打破这种机制,以适应特定场景如Tomcat的类库管理和JSP热加载等需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java命令执行代码流程

当用Java命令去运行一个Class文件时,执行流程如下:
Java命令执行流程

loadClass类加载过程由一下几步组成:
类加载过程
类被加载到方法区中,主要包含:

  • 运行时常量池

  • 类型信息

  • 字段信息

  • 方法信息

  • 类加载的引用

    加载这个类的ClassLoader实例的引用

  • 对应Class实例的引用

    对应堆中Class类型的对象实例,比如com.xxx.Class.class,作为访问方法区中类定义的入口。

类加载器

Java里面有一下几种类加载器:

  • 引导类加载器:负责加载支持JVM运行的jre的lib目录下的核心jar包,比如rt.jar;
  • 扩展类加载器:负责加载支持JVM运行的jre的lib目录下ext扩展目录的jar包;
  • 应用程序加载器:负责加载ClassPath路径下的包,主要是加载自己写的类;
  • 自定义类加载器:负责加载用户自定义目录下的jar或者class文件;

类加载器初始化过程

在Launcher的构造方法中,创建了两个类加载器,分别是ExtClassLoader扩展类加载器,AppClassLoader应用类加载器。
默认使用Launcher#getClassLoader()返回类加载器AppClassLoader加载应用程序。

自定义类加载器

只需要继承java.lang.ClassLoader类,重写其findClass()即可。

双亲委派机制

简单说就是在加载类的时候,先由父类加载器加载,如果父类加载的加载路径下找不到目标Class,则在自己的类加载路径下查找Class,并加载类。
双亲委派机制

为什么要有双亲委派机制呢?

  • 安全机制:防止Java核心API被修改;
  • 避免类重复加载:当父类加载器已经加载该类时,子类加载器就没必要在加载了,保证被加载类的唯一性;

全盘委托机制

指的是当一个Class被ClassLoader加载时,这个Class所依赖的类都将由这个ClassLoader加载,除非显式的使用另外一个ClassLoader。

打破双亲委派机制

只需要继承ClassLoader,重写findClass()和loadClass()方法

	protected Class<?> findClass(String name) throws ClassNotFoundException {
	    try {
	        byte[] data = loadByte(name);
	        return defineClass(name, data, 0, data.length);
	    } catch (Exception e) {
	        e.printStackTrace();
	        throw new ClassNotFoundException();
	    }
	}

    /**
     * 重写类加载方法,实现自己的加载逻辑,不委派给双亲加载
     */
    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 t1 = System.nanoTime();

                //非自定义的类走双亲委派
                if (!name.startsWith("com.xxx.jay")){
                    c = this.getParent().loadClass(name);
                }else{
                    c = findClass(name);
                }

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
}

为什么要打破双亲委派机制

以Tomcat为例,以下问题使用默认的双亲委派机制不能解决:

  • 部署两个应用程序,应用程序依赖同一个类库的不同版本,同名不同版本的类库都需要加载,默认的双亲委派机制不能实现;
  • 部署在同一个Web容器中的应用依赖的相同类库的相同版本可以共享,不然部署一个应用就需要加载一套类库;
  • JSP热加载,JSP编译成Class文件后,如果使用默认的双亲委派机制,修改后的JSP不会被加载,因为已经加载过了,会从方法区中找到。所以需要卸载掉修改的JSP文件,这样就可以实现JSP热加载。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cuidianjay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值