性能加速包: SpringBoot 2.7JDK 17,你敢尝一尝吗 | 京东物流技术团队

前言

众所周知,SpringBoot3.0迎来了全面支持JDK17的局面,且最低支持版本就是JDK17,这就意味着,Spring社区将完全抛弃JDK8,全面转战JDK17。作为JAVA开源生态里的扛把子,Spring可以说是整个JAVA生态的风向标,可以说,当Spring转战JDK17,会很快带领JAVA生态全面的跟进JDK17。而我本篇文章重点讲述Spring版本和JDK17升级中的实践整理。

为什么是Spring Boot 2.7

Spring Boot 3.0是全面放弃JDK8,而Spring社区当然不会把事情做的那么决绝,在推出3.0之前,Spring就开始着手布局JDK17升级。而2.7版本,就是Spring社区为了升级JDK17而推出的过渡版本,具体包括一以下几个方面的升级和改进:

1.支持了JDK 17的新特性,例如switch表达式、文本块、局部变量类型推断等。这使得在Spring应用程序中使用JDK 17的特性变得更加容易和方便。

2.利用了JDK 17的性能优化:JDK 17引入了许多性能优化,例如新的垃圾收集器、线程调度等。Spring 2.7利用了这些性能优化,可以提高Spring应用程序的性能和响应速度。

3.默认配置与JDK 17兼容:Spring Boot 2.7的默认配置与JDK 17兼容,这意味着您不需要进行额外的配置就可以在JDK 17上运行Spring Boot应用程序。这点很重要,Spring Boot 2.7依赖于Servlet 4.0,而Servlet 4.0本身并不直接支持JDK 17, Spring Boot 2.7为了支持JDK 17进行了一些兼容性调整和优化,以使其能够在JDK 17上运行。

4.改进的安全性:JDK 17通过增强加密算法、禁用旧版TLS和SSL协议等增强了安全性。Spring Boot 2.7利用了这些安全改进,提高了应用程序的安全性。

5.持续的性能优化和提升。相比于老系统的2.1到2.3版本,2.7版本对内存管理和bean管理都有很大程度的优化和提升,内存使用更加合理。虽然官网没有给出所谓的性能提升对比,但性能的优化和系统的稳定性是一定加强的。

总之,使用Spring Boot 2.7可以更好地利用JDK 17的特性,提高应用程序的性能和响应速度,同时还可以获得更好的兼容性和安全性。所以通过Spring Boot 2.7过渡升级JDK17,是一种更为温和方式,且遇到的兼容性问题最小。当然这不全是我自顾自说,Spring官方给出了这样的说明:

If you’re currently running with an earlier version of Spring Boot, we strongly recommend that you upgrade to Spring Boot 2.7 before migrating to Spring Boot 3.0.

为什么是JDK17

关于JDK17的新特性和优势,对于它支持的新语法和编程特性,我在此不再赘述,因为网上有很多文章介绍。

对于我落地JDK17的动力主要源于两个方面:一是更为安全的语言特性,二是更加优异的垃圾回收器和性能提升

a. 安全的语言特性

1.安全性首先体现在JDK17对于包扫描和反射的权限控制,可能大家对当年的FastJson漏洞记忆犹新,它的病根在于对反射的滥用。而对于这种反射的滥用,在JDK17里有了更严格的控制。

JDK 17对反射进行了优化,主要表现在对反射调用进行了权限控制。具体来说,它通过setAccessible()方法启动或禁止访问安全检查开关。当参数值为true时,反射的对象在使用时取消安全检查,提高反射的效率;当参数值为false时,反射的对象执行安全检查。这样的优化使得在处理反射调用时,可以更加灵活地控制访问权限。

1.除此之外,JDK 17增强了包扫描的权限控制。在之前的版本中,Java的包扫描是基于类的,而在JDK 17中,它扩展到了对整个包的权限控制。这使得开发者可以更加精细地控制对特定包的访问权限。

2.针对于语法本身,引入了密封的类和接口,具体使用细节大家可以网上查看。通过密封类和接口,进一步增加了面向对象开发的封闭性,提升代码质量的安全可靠。

b. 垃圾收集器

JDK17引入了ZGC作为垃圾收集器,此处引用一下京东科技同事做的关于不同垃圾收集器在不同JDK版本下的压测结果:

压测服务背景:

DOS平台上选择了不同配置的机器(2C4G、4C8G、8C16G),并分别使用JDK8、JDK11和JDK17进行部署和压测。整个压测过程限时60分钟,用180个虚拟用户并发请求一个接口,每次接口请求都创建512Kb的数据。最终产出不同GC回收器的各项指标数据,来分析GC的性能提升效果。

以上的压测结果对于我们来说非常诱人,ZGC配合JDK17的性能对于其他JDK和垃圾收集器组合来说是碾压获胜,且不论任何机器配置下,都推荐使用ZGC,ZGC的停顿时间达到亚毫秒级,吞吐量也比较高。这个对于一个高并发业务场景下,对于资源的优化是非常客观的。

c. OpenJDK17下载地址

提供了一个下载地址: https://adoptium.net/zh-cn/temurin/releases/?version=17&os=linux&arch=x64

行云部署上的实践方案

a. Spring Boot 2.7

1. pom.xml版本依赖

实践的版本选择上我选择了2.7大版本下的最新小版本,即Spring Boot 2.7.17版本。pom.xml依赖如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.jd.magnus</groupId><artifactId>magnus-multi-ddd</artifactId><version>1.0.0-SNAPSHOT</version><packaging>pom</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.17</version></parent><modules><module>magnus-multi-ddd-adapter</module><module>magnus-multi-ddd-application</module><module>magnus-multi-ddd-domain</module><module>magnus-multi-ddd-infrastructure</module><module>magnus-multi-ddd-client</module><module>magnus-multi-ddd-worker</module></modules><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><jsf-lite.version>1.0.0-HOTFIX-T2</jsf-lite.version><ump.version>20221231.1</ump.version></properties>
</project>

2. 动态配置

Spring Boot 2.7对动态配置进行了更新。具体来说,Spring Boot 2.7更改了自动配置注册文件的路径和格式,从META-INF/spring.factories变更为META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。

同时,Spring Boot 2.7还引入了新的注解@SpringBootApplication,该注解包含了@EnableAutoConfiguration和@ComponentScan等注解,使得配置更加简洁和方便。此外,Spring Boot 2.7还更新了一些自动配置的类和方法,以支持新版本的Spring Framework和Java。

1.废弃的方法和类删除。列一下主要删除的方法和类:

SpringBootServletInitializer:在Spring Boot 2.7中,该类已经被移除,建议使用SpringBootServletWebServerApplicationContext来代替。
ServletWebServerFactoryCustomizer:这个接口已经从Spring Boot 2.7中移除,可以使用WebServerFactoryCustomizer来代替。
BasicErrorController:这个类已经从Spring Boot 2.7中移除,可以使用ErrorController接口来代替。
ContentNegotiationStrategy:这个接口已经从Spring Boot 2.7中移除,可以使用RequestMappingHandlerMapping的setContentTypeResolver(ContentTypeResolver)方法来代替。
HttpMessageConverters:这个接口已经从Spring Boot 2.7中移除,可以使用HttpMessageConvertingComparator来代替。
HttpMessageConvertingComparator:这个类已经从Spring Boot 2.7中移除,可以使用ComparatorChain来代替。
ServletWebServerFactoryCustomizerBeanPostProcessor:这个类已经从Spring Boot 2.7中移除。
SpringBootApplicationContextLoader:这个类已经从Spring Boot 2.7中移除,可以使用SpringApplicationWebApplicationContext来代替。
SpringBootServletInitializerAutoConfiguration:这个类已经从Spring Boot 2.7中移除,可以使用SpringBootServletWebServerApplicationContextAutoConfiguration来代替。

此外,还有一些被移除的配置属性,例如spring.http.converters.preferred-json-mapper、spring.jackson.serialization-features.default-pretty-print-xml、spring.jackson.serialization-features.sort-property-names-by-default等。其他信息大家可以看Spring的版本更新说明:

github上的release版本说明:

https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.7-Release-Notes

3. 单元测试升级

在Spring Boot 2.7版本,已经不再依赖JUnit4, 而是将Test换成了 JUnit Jupiter, 这也导致之前单元测试使用的方法和注解会产生变化。

常用的一些方法和注解变化如下:

在这里插入图片描述

4. hibernate-validator包依赖问题

Springboot从2.3以后,spring-boot-starter-web中不再引入hibernate-validator,需要手动引入。此处可以直接引用spring-boot-starter-validation的包,里面会间接引用hibernate-validator的包,且版本号可以被spring boot parent统一管理。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>

4. 诊断升级兼容性方法

如果是老项目版本升级,Spring Boot 提供了一种在启动时分析应用程序环境并打印诊断信息的方法,而且还可以在运行时为您临时迁移属性。要启用该功能,请将以下依赖项添加到您的项目中:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-properties-migrator</artifactId><scope>runtime</scope>
</dependency>

b. 行云部署配置

1. 镜像配置

首先需要新的基础镜像包,包括OpenJDK17的。之前行云的镜像市场上是没有相关的镜像的,后来联系科技运维同事帮忙制作了新的镜像,新的镜像包是基于Tomcat应用类型的,大家可以在jdos的中国站的景象市场搜索到。镜像名如下,:

base_tomcat/java-jd-centos7-jdk17-tomcat8.5.42-ngx197:latest

2. 编译配置

编译配置中,需要选择的JDK版本为17,同时Maven的版本也可以尽量选高一些。因为按照惯例,maven的版本会对JDK的版本兼容性有所不同,一般越是高版本的Maven对JDK17兼容性更好。虽然官方没有明确说明Maven版本支持情况,但我们选择高版本的Maven是比较稳妥的选择,所以在JDOS上我们选择maven-3.9.0版本比较好。

3. JVM参数配置

然后就是配置JVM启动参数,我们需要开启ZGC.具体启动参数以4C8G的资源为例,配置参数如下:

-Xms5324m  -Xmx5324m  -XX:MaxMetaspaceSize=256m -XX:MetaspaceSize=256m  -XX:MaxDirectMemorySize=983m  -Djava.library.path=/usr/local/lib -server -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/export/Logs -Djava.awt.headless=true -Dsun.net.client.defaultConnectTimeout=60000 -Dsun.net.client.defaultReadTimeout=60000 -Djmagick.systemclassloader=no -Dnetworkaddress.cache.ttl=300 -Dsun.net.inetaddr.ttl=300  -XX:+UseZGC  

此处需要注意,ZGC不要配置并行GC线程的数量,并发标记线程数等信息,配置了反而会出现启动报错情况。

c. 兼容性问题说明

关于兼容性问题之前一篇文章里详细介绍了,包括如何兼容京东的UMP, DUCC等。这些中间件的兼容性问题产生主要由于JDK17中对于反射和扫描的安全性检查导致的,一个简单的解决办法是将没开放的module强制对外开放。所以需要一些额外配置。

先整理结论,额外配置集合如下,该集合可以配置在VM 启动参数之中:

--add-opens java.base/sun.security.action=ALL-UNNAMED
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.math=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens java.base/sun.util.calendar=ALL-UNNAMED
--add-opens java.base/java.util.concurrent=ALL-UNNAMED
--add-opens java.base/java.util.concurrent.locks=ALL-UNNAMED
--add-opens java.base/java.security=ALL-UNNAMED
--add-opens java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens java.management/com.sun.jmx.mbeanserver=ALL-UNNAMED
--add-opens java.base/java.net=ALL-UNNAMED
--add-opens java.base/sun.nio.ch=ALL-UNNAMED
--add-opens java.management/java.lang.management=ALL-UNNAMED
--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED
--add-opens java.management/sun.management=ALL-UNNAMED
--add-opens java.base/sun.security.action=ALL-UNNAMED
--add-opens java.base/sun.net.util=ALL-UNNAMED

1. SGM依赖需要加入

--add-opens java.management/java.lang.management=ALL-UNNAMED 
--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED 
--add-opens java.management/sun.management=ALL-UNNAMED

2. R2M需要加入

--add-opens java.base/java.time=ALL-UNNAMED

3. DUCC依赖需要加入

--add-opens java.base/java.util.concurrent=ALL-UNNAMED
--add-opens java.base/java.util.concurrent.locks=ALL-UNNAMED
--add-opens java.base/java.security=ALL-UNNAMED
--add-opens java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens java.management/com.sun.jmx.mbeanserver=ALL-UNNAMED 
--add-opens java.base/java.net=ALL-UNNAMED 
--add-opens java.base/sun.nio.ch=ALL-UNNAMED 

4. AKS依赖需要加入

--add-exports java.base/sun.security.action=ALL-UNNAMED
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.math=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens java.base/sun.util.calendar=ALL-UNNAMED

5. Pfinder依赖需要加入

--add-opens java.base/sun.net.util=ALL-UNNAMED

6. Swagger兼容性配置

分两步:

1.properties配置文件中增加一下配置:

spring.mvc.pathmatch.matching-strategy=ant_path_matcher

1.代码在配置类中新增BeanPostProcessor重写:

/*** 增加如下配置可解决Spring Boot 2.7.15 与Swagger 3.0.0 不兼容问题
**/
@Bean
public BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {return new BeanPostProcessor() {@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {customizeSpringfoxHandlerMappings(getHandlerMappings(bean));}return bean;}private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {List<T> copy = mappings.stream().filter(mapping -> mapping.getPatternParser() == null).collect(Collectors.toList());mappings.clear();mappings.addAll(copy);}@SuppressWarnings("unchecked")private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {try {Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");field.setAccessible(true);return (List<RequestMappingInfoHandlerMapping>) field.get(bean);} catch (IllegalArgumentException | IllegalAccessException e) {throw new IllegalStateException(e);}}};}

7. JDK维度兼容性问题(只挑我遇到的问题重点说)

•JDK11就删除了javaFX库,所以该库下的所有方法在JDK17中不可用。如果你是从JDK8直接升级到JDK17, 需要注意,javaFX下的javafx.util包方法有可能会被大家不小心用到。

以下列举一下javafx.util下的一些常用工具类(项目中尽量不要再用):
在这里插入图片描述

•其次, Java EE(Java Enterprise Edition)规范在 Java 9 之后被重新命名为 Jakarta EE。这是由于 Java EE 规范的开源版本迁移到了 Eclipse Foundation,并改名为 Jakarta EE。

因此有一些包名路径变更,为了兼容JSF,需要手动引入一些JAR包。但由于我们部署环境采用的是外置的Tomcat8,所以还是包含java EE的相关包。不需要额外加入,但本地debug时,需要加入。

尽管 Jakarta EE 是 Java EE 的继任者,但为了保持向后兼容性,许多 Java EE 规范和 API 在 Jakarta EE 中仍然存在,并且在 Jakarta EE 中的命名空间从 javax 变为 jakarta。且一些命名空间也改变了,比如javax包下的方法和属性都不能再试用,例如: javax.xml.bind.*更改为jakarta.xml.bind.*。以下有一个该问题引起的JSF报错修复:

关于JSF启动有报错信息:运行时找不到 javax.xml.bind.JAXBException 类。在 JDK 9 及更高版本中,javax.xml.bind 包被移除了,并且不再包含在标准的 Java SE 中。
如果您的项目依赖于 JAXB API,您可以尝试以下解决方法之一:
如果您使用的是 JDK 8 或更早版本,请确保您的项目使用的是兼容的 JDK 版本。
如果您使用的是 JDK 9 或更高版本,并且需要使用 JAXB API,您可以添加以下依赖项来解决该问题:
<dependency><groupId>jakarta.xml.bind</groupId><artifactId>jakarta.xml.bind-api</artifactId><version>3.0.1</version> <!-- 根据您的需求选择合适的版本 -->
</dependency>

•此处正好多说一下Spring boot 3.0的一个小问题,@Resource在Spring boot 3.0上,已经不再依赖javax.annoation包,所以包路径也由javax.annotation.Resource改为了jakarta.annotation.Resource。当然此处在2.7版本依然兼容,可以不用修改。

以下贴一个报名改动对比图:

在这里插入图片描述

垃圾回收器的话,从JDK14开始,已经删除了CMS,所以在JDK17下,只建议使用ZGC。

还有一个最大的变化是之前的--illegal-access参数不在可用,如果在java 17使用这个参数访问受限的api则会报出InaccessibleObjectException,大多数情况下只要升级了依赖项是不会碰到这个情况的,但如果出现问题,则可以使用--add-opens来对不可访问的api授权。以上的SGM,R2M,DUCC,AKS,Pfinder的兼容性问题都是因为这个特性变化引起的。

脚手架支持

目前最的DDD脚手架已经支持Spring Boot 2.7.17 和JDK17 ,下载脚本如下:

mvn archetype:generate \-DarchetypeGroupId=com.jd.magnus \-DarchetypeArtifactId=magnus-multi-ddd-archetype \-DarchetypeVersion=1.0.0-SNAPSHOT \-DinteractiveMode=false \-DarchetypeCatalog=remote \-Dversion=1.0.0-SNAPSHOT \-DgroupId=com.jdl.sps \-DartifactId=bff-demo1

该脚手架以在京东内部申请为开源项目,开源项目地址如下:

http://xingyun.jd.com/shendeng/openSource/detail/793

IDE配置注意事项

1.在Idea中,需要安装JDK17,然后项目需要配置对应的JDK17版本,截图如下:

1.大家有两种选择:1. 直接安装Idea JDK17插件。 2. 或者自己下载OpenJDK17安装,然后绑定路径。

modules也需要更改Language level, 截图如下:

1.注意:对外的JSF client JDK还要用JDK8进行打包,也不要在client JDK中使用JDK17的新语法特性。因为外部依赖系统不一定是JDK17版本的。

2.本地Debug注意事项。

当本地debug时,需要配置debug的启动参数,配置VM options,并将上面【行云部署上的实践方案-c.兼容性问题说明】章节中所说的兼容性问题配置添加到该处。如下图所示:

此方法也适用于本地debug JUnit Test单元测试本地调试时用。当然,如果为了避免每个单元测试都要手动配置,可以点击图中的Edit configuration templates,配置模板,做到一劳永逸。具体配置如下图所示:

1.Maven test注意事项。

同理,在使用maven命令对工程进行test命令时,也需要额外配置启动参数,来兼容JDK17订单安全性检查,需要在pom文件中的maven-surefire-plugin增加如下配置:

总结

目前,将部门内的京旗API服务, 发货平台BFF服务,物流发货商家基础信息服务作为试点,已经在行云测试环境上用JDK17+Spring Boot2.7版本进行试运行,京东三方依赖包括JSF lite版本,ducc, easyJob,jmq, 云redis, ump, pfinder。经测试,兼容性没有太大问题,服务可用。后续还会进一步观察和测试。

据我了解,现在开源社区里,以apache为代表的大型开源项目都对JDK17有了不错的兼容, 未来可以逐步再从Spring Boot 2.7升级到Spring Boot 3.0。

作者:京东物流 赵勇萍

来源:京东物流 自猿其说 Tech 转载请注明来源

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Arcgis中利用模型构建器统一栅格数据的行列号

1、统一&#xff08;X,Y) 方法&#xff1a;"数据管理工具箱"→"Projections and Transformations"→"Raster"→"Project Raster" 构建模型 这里以行列号最小的栅格&#xff08;X,Y&#xff09;为准&#xff08;其实也就是栅格数据的空…

网络编程day3作业

多进程实现TCP并发服务器 #include<myhead.h>#define PORT 8888 #define IP "192.168.125.130"void hadder(int signo) {if(signo SIGCHLD){while(waitpid(-1,NULL,WNOHANG) > 0);} }int information_exchange(int newfd,struct sockaddr_in cin) {char b…

Redis原理之网络模型笔记

目录 1. 阻塞IO 2. 非堵塞IO 3. IO多路复用 ​3.1 select 3.2 poll 3.3 epoll 4. 信号驱动IO 5. 异步IO 6. Redis是单线程还是多线程 Redis采用单线程模型&#xff0c;这意味着一个Redis服务器在任何时刻都只会处理一个请求。Redis的网络模型涉及到阻塞I/O&#xff08;Blo…

Mac managing Multiple Python Versions With pyenv 【 mac pyenv 管理多个python 版本 】

文章目录 1. 简介2. 安装2.1 brew 安装 pyenv2.2 脚本安装 3. pyenv 安装 Python4. 卸载 python5. 管理 python 1. 简介 Pyenv 是一个用于管理和切换多个 Python 版本的工具。它允许开发人员在同一台计算机上同时安装和使用多个不同的 Python 版本&#xff0c;而无需对系统进行…

STM32与Freertos入门(三)任务的创建、删除

1、串口配置 首先将串口进行配置&#xff0c;后续经常会应用&#xff0c;具体步骤点击&#xff1a;串口配置。 2、任务 创建一个任务&#xff0c;就是开辟一个空间、每个任务中都会有while&#xff08;1&#xff09;死循环。 2.1相关函数 动态创建&#xff1a;xTaskCreate…

vp与vs联合开发-通过CogAcqFifoTool工具连接相机

1.完成相机硬件配置后 2.完成vp与vs联合开发配置功能后 1.创建winform 项目 目的 : 搭建 界面应用 2. 1. vpp文件存入 项目的debug 目录中 目的&#xff1a; 在项目中加载本地vpp文件 读取相机工具 1.控件CogRecordDisplay 用于显示相机拍摄照片和实施显示的窗口 2和3 …

TortoiseGit通过SSH连接配置,生成SSH密钥方法

生成SSH密钥&#xff1a; Win环境下命令(git ssh key是可以自定义命名的)&#xff1a; ssh-keygen -t ed25519 -C "git ssh key" && start "" "C:\Windows\notepad.exe" "C:\Users\%username%\.ssh\id_ed25519.pub" 打开cm…

弹幕情感分析可视化

弹幕情感分析可视化 引言1. 弹幕数据爬取2. 弹幕数据处理3. 弹幕数据可视化4. 弹幕情感分析5. 创新点&#xff1a;弹幕情感倾向分布 引言 当今互联网时代&#xff0c;大量的弹幕数据蕴含着丰富的信息&#xff0c;通过对这些数据进行分析和可视化&#xff0c;我们能够深入了解用…

【C语言】自定义类型——枚举、联合体

引言 对枚举、联合体进行介绍&#xff0c;包括枚举的声明、枚举的优点&#xff0c;联合体的声明、联合体的大小。 ✨ 猪巴戒&#xff1a;个人主页✨ 所属专栏&#xff1a;《C语言进阶》 &#x1f388;跟着猪巴戒&#xff0c;一起学习C语言&#x1f388; 目录 引言 枚举 枚举…

idea添加外部jar包

在日常开发中在lib包的里面添加了外部的jar&#xff0c;如何将外部的包添加到java类库中&#xff0c;这样项目就可以引用相应的jar包&#xff0c;操作如下&#xff1a; 1.先将需要的jar复制到lib包如下&#xff0c;如下截图&#xff0c;图标前面没有箭头&#xff0c;表示还未添…

清晨早安问候祝福语精选,早晨的微笑是全天幸福的开始

1、真情是大海&#xff0c;一辈子不枯&#xff1b;缘分是桥梁&#xff0c;一辈子相连&#xff1b;友情是棵松&#xff0c;一辈子常青&#xff1b;短信是条路&#xff0c;一辈子畅通&#xff01;清晨的鲜花&#xff0c;永远芬芳&#xff01;结下的缘分&#xff0c;永远不忘&…

【华大】HC32F420JATB-LQ48学习资料及开发环境

1. 产品特点 ⚫ 84MHz Cortex-M4 32位CPU平台 ⚫ 128K 字节 FLASH 存储器&#xff0c;具有擦写保护功能 ⚫ 24K 字节 RAM 存储器 ⚫ 6 通道 DMAC ⚫多达 52 个通用 I/O 管脚 ⚫ 时钟、晶振 ‒ 外部高速晶振 8MHz~32MHz ‒ 内部高速时钟 22MHz~24MHz ‒ 内部低速时钟 3…