类的加载过程

在使用java命令运行主类(main)的时候,首先要通过类加载器将类加载到JVM内存中去。主类在运行过程中如果用到其他的类就会逐步加载这些类。jar包里的类并不是一次性加载的,是使用的时候才加载的。

类加载过程分为以下几步:

加载 》验证 》准备 》解析 》初始化 》使用 》卸载

1、加载:在硬盘上通过IO读入字节码文件,使用到类的时候才会加载,例如调用main()方法,new对象等等。

2、验证:校验字节码文件的正确性

3、准备:给类的静态变量分配内存,并且赋予默认值

4、解析:将符号引用替换为直接引用,该阶段会把一些静态方法替换为指向数据所存内存的地址指针或句柄,即静态链接过程(类加载期间完成)。动态链接是在程序运行期间完成的,将符号引用替换为直接引用。

5、初始化:对类的静态变量初始化为指定值,执行静态代码块。

双亲委派机制

双亲委派机制就是在加载某个类的时候会先委托父类加载器(爸爸)加载,父类加载器就会继续委托其父类加载器(爷爷辈)加载,如果所有父类加载器都没有找到目标类,则在自己的加载类路径中查找目标类进行加载。简言之就是有事情做的时候,先交给爸爸做,爸爸做不了就交给爷爷做,爷爷也做不了就只能自己做了。也就是拼爹机制。

假设你自己写了一个类Test.当在加载Test的时候,应用程序类加载器会委托扩展类加载器加载,扩展类加载器会委托启动类加载器加载,启动类加载器在加载路径中无法找到Test类,就退回给扩展类加载器,扩展类加载器收到回复,就在自己的加载类路径中查找该类,找不到就退回给应用程序加载器加载。应用程序类在加载类路径中查找要加载的类进行加载。

为什么要设置双亲委派机制呢:

1、避免重复加载

2、沙箱安全机制,避免核心API库被篡改。(比如你自己写了一个String类,是不会加载的)

自定义加载器

要实现自定义加载器只需要继承ClassLoader类,该类有两个核心方法,

  • loadClass(String, boolean),实现了双亲委派机制,大体逻辑
  1. 首先,检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接返回。
  2. 如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加载器加载(即调用parent.loadClass(name, false);).或者是调用bootstrap类(启动类)加载器来加载。
  3.  如果父加载器及bootstrap类加载器都没有找到指定的类,那么调用当前类加载器
    的findClass方法来完成类加载。还有一个方法是findClass,默认实现是抛出异常,所以我们自定义类加载器主要是重写
  • findClass方法。
 public class MyClassLoaderTest {
  static class MyClassLoader extends ClassLoader {
  private String classPath;    public MyClassLoader(String classPath) {
    this.classPath = classPath;
  }   private byte[] loadByte(String name) throws Exception {
    name = name.replaceAll("\\.", "/");
    FileInputStream fis = new FileInputStream(classPath + "/" + name
       + ".class");
    int len = fis.available();
    byte[] data = new byte[len];
    fis.read(data);
    fis.close();
    return data;
} protected Class<?> findClass(String name) throws ClassNotFoundException{
   try {
    byte[] data = loadByte(name);
     //defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组。
     return defineClass(name, data, 0, data.length);
     } catch (Exception e) {
       e.printStackTrace();
    throw new ClassNotFoundException();
     }
   } } public static void main(String args[]) throws Exception {
     MyClassLoader classLoader = new MyClassLoader("D:/test");
     Class clazz = classLoader.loadClass("com.jvm.User1");
    Object obj = clazz.newInstance();
     Method method= clazz.getDeclaredMethod("sout", null);38 method.invoke(obj, null);
    System.out.println(clazz.getClassLoader().getClass().getName());
  }
} 运行结果:
=======自己的加载器加载类调用方法=======
com.jvm.MyClassLoaderTest$MyClassLoader

打破双亲委派机制

在以下几种情况下需要打破双亲委派机制:

1、同一个容器里面部署多个应用,这几个应用都依赖于同一个第三方类库的不同版本

2、多个应用共享同一个版本的类库。

3、容器依赖的类库与应用程序的类库分开

Tomcat自定义加载器

Tomcat是个web容器, 那么它要解决什么问题: 
1. 一个web容器可能需要部署两个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。 
2. 部署在同一个web容器中相同的类库相同的版本可以共享。否则,如果服务器有10个应用程序,那么要有10份相同的类库加载进虚拟机,这是扯淡的。 
3. web容器也有自己依赖的类库,不能于应用程序的类库混淆。基于安全考虑,应该让容器的类库和程序的类库隔离开来。 
4. web容器要支持jsp的修改,我们知道,jsp 文件最终也是要编译成class文件才能在虚拟机中运行,但程序运行后修改jsp已经是司空见惯的事情,否则要你何用? 所以,web容器需要支持 jsp 修改后不用重启。

Tomcat 如果使用默认的类加载机制行不行? 
答案是不行的。为什么?

1、如果使用默认的类加载器机制,那么是无法加载两个相同类库的不同版本的,默认的累加器是不管你是什么版本的,只在乎你的全限定类名,并且只有一份。

2、默认的类加载器是能够实现的,因为他的职责就是保证唯一性。

3、同1。

4、我们想我们要怎么实现jsp文件的热修改,jsp 文件其实也就是class文件,那么如果修改了,但类名还是一样,类加载器会直接取方法区中已经存在的,修改后的jsp是不会重新加载的。那么怎么办呢?我们可以直接卸载掉这jsp文件的类加载器,所以你应该想到了,每个jsp文件对应一个唯一的类加载器,当一个jsp文件修改了,就直接卸载这个jsp类加载器。重新创建类加载器,重新加载jsp文件。

CommonClassLoader、CatalinaClassLoader、SharedClassLoader和WebappClassLoader则是Tomcat自己定义的类加载器,它们分别加载/common/*/server/*/shared/*(在tomcat 6之后已经合并到根目录下的lib目录下)和/WebApp/WEB-INF/*中的Java类库。其中WebApp类加载器和Jsp类加载器通常会存在多个实例,每一个Web应用程序对应一个WebApp类加载器,每一个JSP文件对应一个Jsp类加载器。

  • commonLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;
  • catalinaLoader:Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;
  • sharedLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;
  • WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见;

从图中的委派关系中可以看出:

  • CommonClassLoader能加载的类都可以被Catalina ClassLoader和SharedClassLoader使用,从而实现了公有类库的共用,而CatalinaClassLoader和Shared ClassLoader自己能加载的类则与对方相互隔离。
  • WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader实例之间相互隔离。
  • JasperLoader的加载范围仅仅是这个JSP文件所编译出来的那一个.Class文件,它出现的目的就是为了被丢弃:当Web容器检测到JSP文件被修改时,会替换掉目前的JasperLoader的实例,并通过再建立一个新的Jsp类加载器来实现JSP文件的HotSwap功能。

01-Java类加载机制详解的更多相关文章

  1. JAVA类加载机制详解

    “代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,却是变成语言发展的一大步”,这句话出自<深入理解JAVA虚拟机>一书,后面关于jvm的系列文章主要都是参考这本书. JAV ...

  2. Java 类加载机制详解

    一.类加载器 类加载器(ClassLoader),顾名思义,即加载类的东西.在我们使用一个类之前,JVM需要先将该类的字节码文件(.class文件)从磁盘.网络或其他来源加载到内存中,并对字节码进行解 ...

  3. Java类加载器详解

    title: Java类加载器详解date: 2015-10-20 18:16:52tags: JVM--- ## JVM三种类型的类加载器- 我们首先看一下JVM预定义的三种类型类加载器,当一个 J ...

  4. JVM类加载机制详解(二)类加载器与双亲委派模型

    在上一篇JVM类加载机制详解(一)JVM类加载过程中说到,类加载机制的第一个阶段加载做的工作有: 1.通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件).而获取的方式,可 ...

  5. JVM类加载机制详解

    引言 如下图所示,JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 加载 在加载阶段,虚拟机需要完成以下三件事情: 1)通过一个类的全限定名来获取定义此 ...

  6. Java 反射机制详解(下)

    续:Java 反射机制详解(上) 三.怎么使用反射 想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属 ...

  7. Java 反射机制详解(上)

    一.什么是反射 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java ...

  8. java异常处理机制详解

    java异常处理机制详解 程序很难做到完美,不免有各种各样的异常.比如程序本身有bug,比如程序打印时打印机没有纸了,比如内存不足.为了解决这些异常,我们需要知道异常发生的原因.对于一些常见的异常,我 ...

  9. Java SPI机制详解

    Java SPI机制详解 1.什么是SPI? SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制.SPI是一种动态替换发现的机制, 比如有个 ...

  10. Java程序员的必备知识-类加载机制详解

    类加载器的概念 类加载器是一个用来加载类文件的类. Java源代码通过javac编译器编译成类文件.然后JVM来执行类文件中的字节码来执行程序.类加载器负责加载文件系统.网络或其他来源的类文件. JV ...

随机推荐

  1. python——模块(Module)的概念、使用以及安装第三方模块

    一.模块定义 python中,一个.py文件就是一个模块(Module). 使用模块的好处:1.提高了代码的可维护性.我们把函数进行分组,分别放在不同的模块中.2.编写代码不必要从0开始,当一个模块编 ...

  2. SpringBoot之【mybatisplus】代码生成器

    1.概述. AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity.Mapper.Mapper XML.Service.C ...

  3. springboot搭建项目,实现Java生成随机图片验证码。

    这篇文章主要介绍了如何通过Java如何生成验证码并验证.验证码的作用我想必大家都知道,话不多说开始实施! 首先创建一个springboot项目以下是项目结构,内有utli工具类.存放生成图片验证码方法 ...

  4. Mysql 5.7.28离线包下载与配置

    下载链接:https://pan.baidu.com/s/1uPbBknyIebQRDt4k_RA58Q   提取码:14zi 将下载文件进行解压,我解压位置为:D:\Program Files\my ...

  5. DDMS files not found: xxx\hprof-conv.exe

    出现如下错误: DDMS files not found: xxx\hprof-conv.exe The connection to adb is down, and a severe error h ...

  6. C#开发微信小程序(四)

    导航:C#开发微信小程序系列 关于小程序项目结构,框架介绍,组件说明等,请查看微信小程序官方文档,关于以下贴出来的代码部分我只是截取了一些片段,方便说明问题,如果需要查看完整源代码,可以在我的项目库中 ...

  7. Android组件体系之BroadcastReceiver小结

    1.常见分类    BroadCastReceiver,按注册方式可以分为静态广播接收器和动态广播接收器.    静态广播接收器:不受程序是否启动的约束,当应用程序关闭之后,还是可以接收到广播(一般广 ...

  8. C# -- 使用缓冲区进行文件下载操作

    C# -- 使用缓冲区进行文件下载操作 1. 为避免下载超大文件占用内存资源,文件下载使用缓冲区,一点一点读取文件资源. string str0 = @"ftp://localhost:21 ...

  9. NSwag.AspNetCore常用功能介绍

    对于asp.net core 下的Swagger,之前一直用Swashbuckle的,因为官方推荐,再加上有老张的博客助力<从壹开始前后端分离[ .NET Core2.0/3.0 +Vue2.0 ...

  10. python3抓取淘宝评论内容

    好久没有写爬虫了,今天研究了下淘宝商品评论的内容. 一开始用最简单的方法,挂代理,加请求头,对网页请求,是抓不到数据的,在网上找了一些相关文章,也基本已经过时了,就是网站逻辑有改动,用旧的方法是抓不到 ...