类加载,双亲委派

2022-03-10  本文已影响0人  小周爱吃瓜

类加载机制:

指的是将类的字节码文件包含的数据写入到内存中。 关于字节码文件可以用javac ,javap -v xxx.class文件查看. 也可以用bytecode viewer工具查看.

字节码文件--->内存--->数据访问

来源: 可以从本地系统,网络,zip包,动态编译,动态代理,加密文件获取.

1.装载: 通过全类名获取二进制流进行加载,同时方法区和堆就同时有了数据. 2.验证:是否符合JVM规范: 2.1 文件格式 字节码文件地址值规范,版本号 2.2 元数据信息是否规范 2.3 符号引用 等 3.准备阶段: 为非final的静态变量赋值,设置基本变量的默认初始值. 4.解析: 符号引用转化成直接引用。 比如调用方法a(),a()地址为#f00`,这个a就是符号引用,f00就是直接引用, 加载时期就能决定的叫做静态的链接,一些代码要在运行时才能决定叫做动态链接. 5.初始化 说白了就是构造方法的调用过程. 由开发者决定那些数据被初始化. 包括静态代码块,构造方法,构造代码块,成员变量数据等. 6.使用: 主动使用类的时候,包括new,Classforname,初始化子类及其父类等。 7.卸载: 常问 7.1 类实例被回收了,堆中没有该类的实例 7.2 加载该类的ClassLoader被回收了 7.3 没有被引用了 总结: 自己挂了,没有引用它了,加载器也被回收了.

双亲委派: 负责读取java字节码文件,并且转化成java.lang.Class类的一个实例代码模块。

BootstrapClassLoader 顶层: 加载/jre/lib 可以理解成核心类的class

ExtensionClassLoader 中间: 加载平台扩展的jar包

AppClassLoader下层: 加载classpath中指定的jar包

好处: 安全,不然随便写个字符串都能被加载。 效率高,加载过的不会被加载了 重写loadClass,可以指定自己的类加载器 findClass(不要轻易尝试,会带来很多问题)

为什么要打破? 比如Tomcat,部署了不同版本的包,A1,A2版本,路径相同下的类名相同, 这样会出现覆盖的情况,各自需要的类会冲突。

JDBC 在bootxxClass加载的类要用AppClassLoader加载,矛盾了 Tomcat 自己的WebAppClassLoader加载自己目录下的class文件,不会向上传递.

第二天对第一天的补充:

类加载机制的好处:
沙箱机制: 不能随意写个String就被加载了
避免类的重复加载
package com.daily.tuling726;

import lombok.SneakyThrows;
import sun.misc.IOUtils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class MyClassLoader extends ClassLoader{

private String path;

public MyClassLoader(String path) {
    this.path = path;
}

@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
//定义名称
    if (name.equals("xxx")){
        name = "

name – The binary name of the class
resolve – If true then resolve the class";
}
return super.loadClass(name, resolve);
}

//加载文件
@SneakyThrows
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = getClassData(path);
return defineClass(name,getClassData(path),0,data.length);
}

byte[] getClassData(String path) throws IOException {
    FileInputStream fileInputStream = new FileInputStream(path);
    int length = fileInputStream.available();
    byte[] bytes = new byte[length];
    int read = fileInputStream.read(bytes);
    return bytes;
}

}

ServiceLoader:

            ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
            Iterator<Driver> driversIterator = loadedDrivers.iterator();

DriverManage是BootStrapCLassLoader加载进来。 com.xx.Driver是AppClassLoader加载进来的.

但是SPI的类不是,

DriverManager
static { loadInitialDrivers(); println("JDBC DriverManager initialized"); } 收到加载范围限制,父类加载器需要委托子类加载器加载Class问价,这个时候就打破了双亲委派.
各种服务商提供服,Java提供接口,这样就能提供替换,热部署。

双亲委派只是建议,不是强制的

上一篇下一篇

猜你喜欢

热点阅读