当前位置 : 主页 > 编程语言 > 其它开发 >

类加载

来源:互联网 收集:自由互联 发布时间:2022-07-02
加载-----连接(验证---准备---解析)------初始化: 加载就是 将类的二进制字节码载入JVM中、将这个字节流代表的存储静态存储结构转化为方法区的运行时数据结构、在堆中生成一个ja

加载-----连接(验证---准备---解析)------初始化:

  • 加载就是 将类的二进制字节码载入JVM中、将这个字节流代表的存储静态存储结构转化为方法区的运行时数据结构、在堆中生成一个java.lang.Class 对象,表示堆方法区中类的引用

  • 验证就是验证加载进来的类是不是对jvm有害。文件格式验证(在类装载过程)、元数据验证(在准备的那一步用到了元素据)、字节码验证(贯穿流程)、符号引用验证(贯穿流程)。这四个验证并不是严格按照这个顺序走下来的,是贯穿整个流程的过程。

  • 准备就是对静态变量与常量设置默认值。为类的静态变量分配内存并赋值,当前类型的默认值。

  • 解析就行将类中的符号引用(是一些描述信息比如字段、方法,因为在文件中我们没办法描述他是这个字段,也不能指向真实内存。)转化为直接引用(指向一个真正的地址)

  • 按照我们的意愿进行初始化。

扩展:初始化顺序

  • 父类的静态变量、静态代码块

  • 子类的静态变量、静态代码块

  • 父类的非静态变量、非静态代码块、构造方法

  • 子类的非静态变量、非静态代码块、构造方法

 

类加载器

  • 启动类(根)加载器:

  • 扩展类加载器:加载java平台中扩展功能的一些jar包

  • 应用程序()加载器:加载classpath中指定的jar包及classpath所指定目录下的类和jar包。

  • 自定义加载器:通过自定义的加载器加载class。

 

双亲委派机制

类加载器收到类加载的请求、将这个请求向上委托给父类加载器去完成,一直向上委托,直到启动类加载器、启动加载器检查是否能够加载当前这个类,能加载就使用当前加载器,否则,抛出异常,通知子类加载器进行加载。

好处:1.为了防止内存中存在多份同样的字节码,使用了双亲委派机制(它不会自己去尝试加载类,而是把请求委托给父加载器去完成,依次向上)

如何打破这个机制:只要我自定义个ClassLoader,重写loadClass方法(不依照往上开始寻找类加载器),那就算是打破双亲委派机制了。

eg/:

  • tomcate:tomcate是一个web容器,可能需要部署多个应用程序,但是不能程序可能依赖同一个第三方库的不同版本,但是不同版本下的某个类的全路径名可能是一模一样的,比如多个应用都要依赖C.jar,但是A应用需要1.0.1版本,B应用需要1.0.3版本,这两个版本中都有一个全路径名为com.C.xx类,如果不打破那么无法加载多个相同的类。所以tomcate破环双亲委派机制,提供隔离机制,为某个web容器单独提供一个(webAppClassLoader)应用类加载器。这样每个应用又自己的类加载器,该加载器重写了loadclass方法,会优先加载当前应用目录下的类,加载不了再给它的父类去加载(sharedClassLoader)。

  • spi机制(Service Provider Interface服务提供接口)

    首先定义一种标准服务接口,服务提供者去实现这个接口,然后放入META-INF/services/中。当有人需要调用时,可以通过查找这个jar包的META-INF/services/中的配置文件,配置文件中有接口的具体实现类名,可以根据这个类名进行加载实例化。

主要使用场景就是自身只提供接口规范,然后让第三方提供接口的具体实现。如:jdbc驱动类加载,当然自己也可以提供接口和实现 类,然后运行时选择要使用的实现,另外根据这种机制可以扩展很多功能,如springboot的spi机制

 
网友评论