【学习笔记】深入理解JVM之类加载机制

news2024/11/17 11:40:18

【学习笔记】深入理解JVM之类加载机制

以后基本上都在语雀上面更新,大家有兴趣可以看看嗷!
首发地址: 知识库

文章流程图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6mcrGx0K-1671638019183)(/Users/tiejiaxiaobao/Library/Application Support/typora-user-images/image-20221221234802063.png)]

1、概述

首先我们先来看看一个 Class 文件所需要经过的一个流程图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SQMDXw9o-1671638019183)(/Users/tiejiaxiaobao/Library/Application Support/typora-user-images/image-20221218145747775.png)]

而我们今天要重点需讲的就是 类加载器 这部分。

在讲类加载器之前先问一个问题——什么是 Class 文件?

Class 文件是一组 8 字节为基础单位的二进制文件,各个数据项项目严格按照顺序紧凑地排列在文件之中,中间没有添加任何分隔符,这使得 Class 文件中存储的内存内容部分都是程序运行的必要数据,没有空隙存在。

通过上面的回答我们知道 Class 文件,是一个以 8 自己为基础单位的二进制文件,那如果遇到一个需要 占用8字节以上的的空间数据项时会怎么办?

当出现占用超过 8 以上空间的数据项时,则会采用 高位在前 的方式分割成若干个 8 个字节进行存储。

补充:

一般 Class 文件的头四个字节被称为 魔数(Magic Number) ,它的作用就是确定这个文件是否为一个能被虚拟机接受的 Class 文件。

2、类加载机制

那什么又是类加载机制呢?

Java虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行 校验、转换解析和初始化 ,最终形成可以被虚拟机直接使用的Java类型,这个过程被称作虚拟机的类加载机制。

类加载的过程图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kgFGj2lU-1671638019184)(/Users/tiejiaxiaobao/Library/Application Support/typora-user-images/image-20221218151529117.png)]

2.1 加载

注意此处的 “加载” 是 ‘’类加载“ 过程中的一个阶段, 大家不要弄混了嗷。

在加载阶段,Java 虚拟机需要完成以下三件事:

  • 通过一个类的 全限定名 来获取定义此类的二进制字节流。
  • 将这个 字节流 所代表的 静态存储结构 转化为方法区的 运行时数据结构
  • 在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口。

补充:

可以获取二进制字节流的方式:

  • 从ZIP压缩包中读取,这很常见,最中成为日后JAR、EAR、WAR的格式基础。
  • 从网络中获取,这种场景最低昂行的应用就是 Web Applet
  • 运行时计算生成,这种场景使用得最多的就是 动态代理 技术,在 java.lang.reflect.Proxy 中,就是用了 ProxyGenerator.generateProxyClass() 来为特定接口生成形式为 "*$Proxy" 的代理类的二进制字节流。
  • 从数据库中读取。
  • 其他文件生成。

2.2 验证

验证是链接阶段的第一步,这一阶段的目的是确保 Class 文件的字节流中包含的信息符合 《Java虚拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。

举个例子:

我们知道 Class 文件并不一定都是 Java 源码编译而来,它可以使用包括靠键盘 0和1 直接在二进制编辑器中敲出 Class 文件。如果不进行此方面的验证,对其完全信任的话,可能会有恶意的企图的字节码流程,而导致整个系统搜到破坏。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Jr9QB1u-1671638019184)(/Users/tiejiaxiaobao/Library/Application Support/typora-user-images/image-20221218200905808.png)]

所以说验证字节码是 Java 虚拟机自我保护的一项必要措施。

验证阶段是是十分严谨的,直接决定了 Java虚拟机 是否能承受恶意代码的攻击。验证阶段大致分为以下四个阶段:

  • 文件格式验证
  • 元数据验证
  • 字节码验证
  • 符号引用验证

♣️ 2.2.1 文件格式验证

第一阶段就是需要验证字节流是否符合 Class 文件格式的规范,并且能被当前版本的虚拟机处理。这一阶段可能包括下面这些验证点:

  • 是否以魔数 0xCAFEBABE 开头。
  • 主、次版本号是否在当前的 Java 虚拟机接受范围之内。
  • 常量池的常量中是否有不被支持的常量类型。
  • 指向常量的各种索引值中是否有指向不存在的常量或不符合类型的常量。
  • CONSTANT_Utf8_info型的常量中是否有不符合UTF-8编码的数据。
  • Class 文件中各个部分及文件本身是否有被删除的或附加的其他信息。

目的:

上述的验证阶段主要是为了保证输入的字节流能正确地解析并存储于方法区内。这个阶段是基于二进制字节流进行的,只有通过了这个阶段的验证之后,这段字节流才被允许进入Java虚拟机内存的方法区中进行存储。所以后面的三个验证阶段都是基于 方法区的存储结构来进行的

♣️ 2.2.2 元数据验证

第二阶段是对字节码描述的信息进行语义分析,以保证其描述的信息符合《Java语言规范》要求,这个阶段可能包括的验证点如下:

  • 这个类是否有父类(除了 java.lang.Object 之外,所有的类都应当有父类)。
  • 这个类的父类是否继承了不允许被继承的类(被final修饰的类)。
  • 如果这个类不是抽象类,是否实现了其父类或接口之中要求实现的所有方法。
  • 类中的字段、方法是否与父类产生矛盾(例如覆盖了父类的final字段,或者出现不符合规则的方法重载,例如方法参数都一致,但是返回值类型却不同等)。

目的:

是对类的元数据信息进行语义校验,保证不存在《Java语言规范》定义相悖的元数据信息。

♣️ 2.2.3 字节码验证

本阶段是真个验证阶段最为复杂的一个阶段,主要目的是通过数据流分析和控制流分析,确定程序语义是合法的、符合逻辑的。本阶段是对 方法体(Class文件中的Code属性) 进行校验分析,保证被校验类的方法在运行时不会做出未来虚拟机安全的行为。

例如:

  • 保证任意时刻操作数栈的数据类型与指令代码序列都能配合工作,例如不会出现类似于“在操作栈放置了一个int类型的数据,使用时却按照long类型来加载本地变量表中” 这样的情况。
  • 保证跳转指令都不会跳转到方法体以外的字节码指令上。
  • 保证方法体中的类型转换总是有效的,例如可以把一个子类的对象赋值给父类数据类型,这样是安全的,但是把父类对象赋值给自类数据类型,甚至把对象赋值给与它毫无继承关系、完全不想干的一个数据类型,则是危险和不合法的。

如果有一个方法体中的字节码没有通过字节码的验证,那它肯定是有问题的。但是如果通过了验证也不能百分之百的保证他是安全的。

♣️ 2.2.4 符号引用验证

最后一个阶段的校验行为发生在虚拟机将符号转化为直接引用的时候,这个转化动作将在连接的第三阶段( 解析阶段中发生 )。其可以看作是对类自身以为(常量池中各个符号引用)的各类信息进行匹配性校验,通俗来说就是,该类是否缺少或者被禁止访问它依赖的某些外部类、方法、字段等资源。本阶段通常需要校验下列内容:

  • 符号引用中通过 字符串描述全限定名 是否能找到 对应的类
  • 指定类中 是否存在符合方法的字段 描述符简单名称 所描述的 方法和字段
  • 符号引用中的类、字段、方法的可访问性( private、protected、public、<package> ) 是否可被当前类访问。

本阶段的主要目的就是确保解析行为能正常执行,如果无法通过 符号引用验证 阶段 Java虚拟机 将会抛出一个 java.lang.IncompatibleClassChangeError 的子类异常,典型的如:java.lang.IllegalAccessError、java.lang.NoSuchFieldError、java.lang.NoSuchMethodError 等。

♣️ 2.2.5 总结

验证阶段对于虚拟机的类加载机制来说,是一个非常重要的、但却不是必须要执行的阶段,因为验证阶段只有通过或者不通过的差别,只要通过了验证,其后就对程序运行期没有任何影响,如果程序运行的全部代码(包括自己编写的、第三方包中的、从外部加载的、动态生成的等所有代码)都已经被反复使用和验证过了,再生产环境的实施阶段即可以考虑使用 -X verify:none 参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

2.3 准备

准备阶段是正式为类中定义的变量( 静态变量,被 static 修饰的变量 ) 分配内存并设置变量的初始值的阶段。从概念上讲,这些变量所使用的内存都应当在方法区中进行配置,但应该注意方法区本生就是一个逻辑上的区域。在 JDK1.8 之后,类变量会随着 Class 对象一起存放在 Java 堆中。

注意: 准备阶段进行内存分配的仅包括类变量,而不是实例变量,实例变量将会在对象实例化的时候随着对象一起分配在Java堆中

我们通常情况下数据类型 零值

例如:

public static int value = 123;

如上述代码,value 在准备阶段过后的初始值为0而不是123,因为 这时尚未开始执行任何Java方法,而把 value 赋值为123的 putstatic 指令是程序被编译后,存放于类构造器 <clinit>() 方法之中,所以把 value 赋值为123的动作要到类的初始化阶段才会被执行。

零值表补充:

**[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FLQhhdZm-1671638019184)(/Users/tiejiaxiaobao/Library/Application Support/typora-user-images/image-20221218222700941.png)]**

但是会出现特殊情况:

如果类字段的字段属性表中存在 ConstantValue 属性,那在准备阶段变量值就会被初始化为 ConstantValue 属性所指定的初始值,如果上面代码改为以下情况:

public static final int value = 123;

编译时 Javac 会将为 value 值生成 ConstantValue 属性,在准备阶段虚拟机就会根据 ConstantValue 的设置将 value 赋值为 123。

总结:

  • 为类变量分配内存并切设置该类变量的默认初始值,即零值。
  • 这里不包含使用 final 修饰的 static ,因为 final 在编译的时候机会分配,准备阶段会显示初始化。
  • 这里不会为 实例变量 分配初始化,类变量会分配在方法区中,而实例变量实惠随着对象一起分配到 Java堆中。

2.3 解析

解析过程是 Java虚拟机 将常量池内的 符号引用 替换为 直接引用 的过程。

  • 符号引用: 符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。

  • 直接引用: 直接引用是可以直接指向目标的指针、相对偏移量或者是一个能间接定位到目标的句柄。

解析的流程有以下四个:

  • 类或接口的解析
  • 字段解析
  • 方法解析
  • 接口方法解析

事实上解析操作都是往往伴随着 JVM 在执行过程中完成初始化之后再执行。

2.4 初始化

类的初始化阶段是类加载过程的最后一个步骤,之前介绍的的几个类的加载动作里,除了在 加载阶段 用户应用程序可以通过自定义类加载器的方式局部参与,其余动作完全由 Java 虚拟机来主导控制权。直到 初始化阶段Java 虚拟机才开始真正开始执行类中编写的 Java 程序代码,将主导权移交给应用程序。

而在初始化阶段,则会根据程序员通过程序编码指定的主观计划去初始化类变量和其他资源。

总结:

  • 初始化阶段就是执行类构造器 <clinit>() 方法的过程。
  • 此方法不需要被定义,而javac编译器自动收集类中所有变量值的赋值动作和静态代码块中语句合并而来。
  • 构造器方法中指令按语句在源文件中出现的顺序执行。
  • <clinet>() 不同于类的构造器(<init>()
  • 若该类具有父类,JVM 保证子类的 <client>() 执行前,父类的 <clinit>() 已经执行完毕。
  • 虚拟机必须保证一个类的 <clinit>() 方法再多线程下被同步加锁。

3、类加载器

首先我们要知道什么是 类加载器

通过一个类的全限定名来获取描述该类的二进制字节流 这个动作放到 Java 虚拟机外部去实现,以便让应用程序自己去决定如何获取所需的类。实现这个动作的代码被称为 类加载器(Class Loader)

对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在 java 虚拟机中的 唯一性 ,每一个类加载器都拥有一个独立的类名称空间。通俗一点讲就是:比较两个类是否相等,只有在这两个类是同一个类加载器加载的前提下才有意义。

类加载器一共有以下几种:

名称加载哪的类说明
Bootstrap ClassLoader(启动类加载器)JAVA_HOME/jre/lib无法直接访问
Extension ClassLoader(扩展类加载器)JAVA_HOME/jre/lib/ext上级为 Bootstrap,显示为 null
Application ClassLoader(应用程序类加载器)classpath上级为 Extension
自定义类加载器自定义上级为 Application

类加载器的优先级(由高到低):启动类加载器 -> 扩展类加载器 -> 应用程序类加载器 -> 自定义类加载器

3.1 启动类加载器(Bootstrap ClassLoader)

  • 这个类加载器是使用 C++/C 语言来实现的,嵌套在 JVM 内部。
  • 它用来加载 Java 的核心库(JAVA_HOME/jre/lib),用于提供 JVM 自身需要的类。
  • 并不是继承自 java.lang.Class.ClassLoader ,没有父加载器。
  • 加载扩展类和应用程序类加载器,并指定为他们的父类加载器。

获取启动类能够加载的路径:

    public static void main(String[] args) {
        URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
        for(URL element: urLs){
            System.out.println(element.toExternalForm());
        }
    }

file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/resources.jar
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/rt.jar
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/sunrsasign.jar
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/jsse.jar
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/jce.jar
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/charsets.jar
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/jfr.jar
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/classes

3.2 扩展类加载器(Extension ClassLoader)

  • Java语言编写,由 sun.misc.Launcher$ExtClassLoader 实现。
  • 派生于ClassLoader类。
  • 父类加载器为启动类加载器。
  • java.ext.dirs 系统属性所指定的目录中加载类库,或从 JDK 的安装目录的 jre/lib/ext 子目录(扩展目录)下加载类库。如果用户创建JAR在此目录下,则会自由由扩展类加载器加载。
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
// sun.misc.Launcher$AppClassLoader@18b4aac2

例如:

    public static void main(String[] args) {
        String property = System.getProperty("java.ext.dirs");
        for(String p: property.split(":")){
            System.out.println(p);
        }
    }

输出:

/Users/tiejiaxiaobao/Library/Java/Extensions
/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/ext
/Library/Java/Extensions
/Network/Library/Java/Extensions
/System/Library/Java/Extensions
/usr/lib/java

3.3 应用程序加载器(AppClassLoader)

  • 由Java语言编写,由 sun.misc.Launcher$AppClassLoader 实现。
  • 派生于 ClassLoader 类。
  • 父类加载器为扩展加载器。
  • 它负责加载环境变量 classpath 或系统属性 java.class.path 指定路径下的类库。

3.4 用户自定义类加载器

为什么要自定义类加载器呢?

  • 隔离加载类
  • 修改类加载的方式
  • 扩展加载源
  • 防止源码泄露

那又什么时候去定义呢?

  • 1)想加载非 classpath 随意路径中的类文件
  • 2)都是通过接口来使用实现,希望解耦时,常用在框架设计
  • 3)这些类希望予以隔离,不同应用的同名类都可以加载,不冲突,常见于 tomcat 容器

步骤:

  • 继承 ClassLoader 父类。
  • 要遵从双亲委派机制,重写 findClass 方法 注意不是重写 loadClass 方法,否则不会走双亲委派机制。
  • 读取类文件的字节码。
  • 调用父类的 defineClass 方法来加载类。
  • 使用者调用该类加载器的 loadClass 方法。

4、双亲委派模型

♣️ 什么是双亲委派模型呢?

如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UtWnM5dJ-1671638019184)(/Users/tiejiaxiaobao/Library/Application Support/typora-user-images/image-20221219212226647.png)]

实现:

		protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
								// 首先,检查请求的类是否已经被加载过了 Class c = findLoadedClass(name); if (c == null) {
                try {
                		if (parent != null) {
                			c = parent.loadClass(name, false);
                		} else {
                			c = findBootstrapClassOrNull(name); }
                } catch (ClassNotFoundException e) {
                // 如果父类加载器抛出ClassNotFoundException // 说明父类加载器无法完成加载请求
                }
                		if (c == null) {
                // 在父类加载器无法加载时
                // 再调用本身的findClass方法来进行类加载 c = findClass(name);
                } 
    }
                		if (resolve) { resolveClass(c);
                }
                return c; 
}

♣️为什么使用双亲委派模型呢?(好处)

  • 采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父加载器已经加载了该类时,就没有必要子加载器再加载一次。
  • 其次是考虑到安全因素,java 核心 api 中定义类型不会被随意替换,假设通过网络传递一个名为 java.lang.Integer 的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的 java.lang.Integer,而直接返回已加载过的 Integer.class,这样便可以防止核心API库被随意篡改。

参考

本篇笔记参考:尚硅谷JVM 26 - 36 集

《深入理解Java虚拟机》第三版

第六章—类文件结构

第七章—虚拟机类加载机制

文章地址:https://blog.csdn.net/weixin_43591980/article/details/119916684

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/375814.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何保护阿里云、政采云等云市场三方账号安全?

什么是云市场&#xff1f;根据百度百科释义&#xff0c;云市场是指物联网中分布在不同地点的海量的商品生产者和消费者之间各种经济关系的集合体&#xff0c;是通过相对集中的云平台资源联合物联网各个感知节点信息资源的方式&#xff0c;以运行分布在不同地点的海量的经济交换…

Java——数组

目录 前言 一、数组的定义 二、数组声明和创建 三、三种初始化及内存分析 Java内存分析 三种初始化 静态初始化 动态初始化 数组的默认初始化 数组的四个基本特点 四、下标越界及小结 五、数组的使用 For-Each循环 数组作方法入参 数组作返回值 六、二维数组 七…

项目管理工具dhtmlxGantt甘特图入门教程(十四):导出/导入 Excel到 iCal

这篇文章给大家讲解利用dhtmlxgantt导入/导出Excel到iCal的操作方法。 dhtmlxGantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表&#xff0c;可满足应用程序的所有需求&#xff0c;是完善的甘特图图表库 DhtmlxGantt正版试用下载&#xff08;qun&#xff1b;765665…

中国跨境平台出海,产业带依然是最大优势

对外贸工厂来说&#xff0c;借助跨境电商服务平台开拓海外市场可行吗&#xff1f;2023年2月11日&#xff0c;在郑州荥阳举办的Starday线下招商会联合线上直播荥阳站上&#xff0c;这是很多现场参会的企业负责人面对大屏上的招商介绍宣传时&#xff0c;大脑飞速思考的问题。2023…

android kotlin 协程(六) 源码浅析

android kotlin 协程(六) 源码浅析 前言: kotlin协程源码十分庞大, 本篇只能吧我理解的源码聊一聊,不会特别深入研究,只会浅浅的看看表层. 本来计划协程系列是10篇左右,后续是flow热流冷流之类的, 冷流操作符之类的应该不会在写了, flow当作Rxjava来用就可以,后续可能还会写一…

Bitlocker加密,与解除加密

引文&#xff1a;应为C盘空间不够用了&#xff0c;想着用U盘从新给C盘分下区。操作时才发现我系统里的磁盘都是Bitlocker加密的&#xff0c;分区工具操作不了磁盘&#xff0c;所以就找到一下方法来解决。1&#xff0c;先讲一下解除加密&#xff1a;直接点击 &#xff1a;设置-&…

python pandas 常用方法汇总

前言 一、pandas是什么&#xff1f; 二、使用步骤 1.引入库 2.处理时间序列数据 3.分组聚合&#xff08;groupby&#xff09; 3.1基本方法 3.2具体使用&#xff1a;如图包含三个字段&#xff0c;company、salary、age 总结 Pandas 最最常用函数罗列 Pandas 函数用法示…

软件测试2年半的我,谈谈自己的理解...

软件测试两年半的我&#xff0c;谈谈自己的理解从2020年7月毕业&#xff0c;就成为一名测试仔。日子混了一鲲年&#xff0c;感觉需要好好梳理一下自己的职业道路了&#xff0c;回顾与总结下吧。一、测试的定位做事嘛&#xff0c;搞清楚自己的定位很重要。要搞清楚自己的定位&am…

新手小白根据Forexclub6点建议就能选择到最佳外汇经纪商

选择外汇经纪商很重要&#xff0c;尤其是对于外汇交易者新手而言。 在确定您计划使用的外汇交易员之前&#xff0c;Forexclub建议考虑以下6个因素产品丰富即使在这个阶段&#xff0c;您只对外汇交易感兴趣&#xff0c;拥有期权也是件好事。 大多数外汇经纪商提供对其他金融资产…

Excel工作表不能移动或复制?看看是不是这两个原因

Excel工作表不能移动或复制&#xff1f;今天来看看如何解决。 大家都知道&#xff0c;Excel表格分为工作簿和工作表&#xff0c;工作簿就是整个Excel文件&#xff1b;工作簿里面&#xff0c;也就是Excel表可以有多个工作表。 而各个工作表之间是可以相互移动或复制的&#xf…

C++赋值运算符重载

赋值运算符重载 目录赋值运算符重载示例1&#xff1a;示例2&#xff1a;示例3&#xff1a;示例4&#xff1a;很巧妙的是&#xff0c;在编写这篇文章时&#xff08;2023年2月27日&#xff09;&#xff0c;再加100天就是6月7日&#xff0c;恰好是今年高考的百日誓师&#xff01; …

蓝库云|什么是供应链管理?SCM对制造业的重要性

企业在产品的销售经营上&#xff0c;往往不会考量到供应链管理(SCM)的流程规划&#xff0c;但现今的商业环境与以往不同&#xff0c;高度竞争与客户不断提升的期望&#xff0c;藉由做好供应链管理(SCM)&#xff0c;才能更准时的提供优质产品与优良服务&#xff0c;增强企业竞争…

HTML、CSS学习笔记4(3D转换、动画)

目录 一、空间转换&#xff08;3D转换&#xff09; 1.空间位移 语法&#xff1a; 取值&#xff1a;&#xff08;正负均可&#xff09; 透视&#xff1a; 2.空间旋转 3.立体呈现 二、动画&#xff08;animation&#xff09; 1.动画的使用 先定义动画 再调用定义好的动画 …

YSYY科研试剂DSPE-PEG-Cholesterol;磷脂聚乙二醇胆固醇简介;DSPE-PEG-胆固醇

二硬脂酰磷脂酰乙酰胺-聚乙二醇-胆固醇,DSPE-PEG-CLS&#xff0c;DSPE-PEG-Cholesterol 结构式&#xff1a; 中文名称&#xff1a;二硬脂酰磷脂酰乙酰胺-聚乙二醇-胆固醇英文名称&#xff1a;1,2-distearoyl-sn-glycero-3-phosphoethanolamine-N-[ Cholesterol(polyethylene g…

消息队列介绍和RabbitMQ的安装

1.消息队列 1.1 MQ的相关概念 1.1.1 什么是MQ MQ(message queue)&#xff0c;从字面意思上看&#xff0c;本质是个队列&#xff0c;FIFO 先入先出&#xff0c;只不过队列中存放的内容是message 而已&#xff0c;还是一种跨进程的通信机制&#xff0c;用于上下游传递消息。在…

视频营销活动中7个常见的错误

如今&#xff0c;越来越多的企业在社交媒体平台上开展视频营销活动。与其他传统营销策略不同&#xff0c;视频营销可以为企业带来更多的销售机会。随着越来越多的视频社交媒体平台的出现&#xff0c;营销人员更应该抓住这个机会。但在开始视频创作之前&#xff0c;您需要有一个…

一次查询的全过程

一次查询的全过程&#xff1a; 比方说我这里有一个订单系统&#xff0c;一条查询请求发送过来&#xff0c;它内部是怎么执行的呢&#xff1f; 用户发送请求到业务系统&#xff0c;就会有一条线程来处理这个请求该线程会在数据库连接池里面获取一个JDBC连接MySQL工作线程会监听数…

从零开始的python基础教程(3)

十、Popular Python Packages 1、What are APIs Application Programming Interface 2、Search for Business 3、Hiding API Keys so now when we push our codes to Github repository, our config file will not be there 十一、使用Dyjango构建Web应用程序 1、Your Firs…

九年时间,倾情投入,JumpServer开源堡垒机v3.0正式发布

2023年2月27日&#xff0c;JumpServer开源堡垒机正式发布v3.0版本。在JumpServer开源堡垒机v3.0版本的设计过程中&#xff0c;我们始终秉持着“内外兼修”的原则&#xff0c;旨在进一步提升用户的使用体验&#xff0c;真正用心做好一款开源堡垒机。 在JumpServer v3.0版本中&…

回溯算法(BackTracking)

在许多情况下&#xff0c;回溯算法相当于穷举搜索的巧妙实现。回溯算法的一个具体例子是在新房子里摆放家具&#xff0c;开始什么也不摆放&#xff0c;然后每件家具被摆放在房间的某个位置&#xff0c;如果所有的家具都被摆放得令户主满意&#xff0c;那么算法终止&#xff1b;…