踩了一堆坑,终于把微服务系统全面升级 JDK17 和 SpringBoot3 了

最近正在给自己的开源项目校园博客升级到 JDK17 以及 SpringBoot3,正好记录下升级和踩坑的过程,给大家提供一些解决方案的参考。

先说结论:非常推荐升级JDK17,成本低收益高。至于SpringBoot3.0,迁移成本比较高,坑也会比较多,但如果是新项目的话,还是可以试试的。

PS:项目原来的版本是 JDK8 + SpringBoot2.6。

为什么要升级?

  • JDK17和SpringBoot3也发布了一段时间了,自己对一些新特性也比较感兴趣,尤其是 Native Image 这个玩意。
  • 自己手上刚好有校园博客这个项目,可以用来给进行升级,项目不复杂,但也算五脏俱全,全量升级既可以感受一下变化,也不会太费事。
  • JDK17 是一个长期支持的版本(LTS),现在很多开源应用或者一些组件都在往这上面靠,并且大有一种最低支持 JDK17 的趋势。
  • 自己在公司所接触到的项目也有一部分是使用的JDK17,并且整体有往这方面靠的趋势,新项目都会直接用JDK17。

总的来说就是 兴趣 + 资源 + 趋势。

升级有什么好处?

先来看看 JDK8 -> JDK17 的好处。

  • ZGC垃圾回收器,性能提升
  • 可以使用 var 作为局部变量类型推断标识符
  • 一个文件中可以包含多个public类
  • switch 使用起来更加简洁,可以不用再break了。
  • instanceof 增强
  • 增加不可修改的数据类 record(感觉还是 kotlin 的 data class 好用)
  • Text Blocks文本块

实用性很强,非常舒服。

image.png


再看看 SpringBoot3.0 的一些新特性。

  • 更好的支持 Native Image,使用 GraalVM 构建原生镜像,可以提供显著的内存和启动性能改进
  • 升级到 Spring6.0
  • 升级到 Spring Security 6.0

好吧,感觉上是不如 JDK17 要更有性价比,如果对 Native Image 兴趣不大的话,建议不要升级SpringBoot3.x,因为升级SpringBoot的成本可要比升级JDK高多了。

image.png

升级过程分享

以下的一切内容均基于我已有的项目【校园博客】进行升级和讲解,源码地址:https://github.com/stick-i/scblogs

既然一切都是基于JDK17的,那我们就先升级JDK吧!

升级JDK17

下载安装

安装JDK17,这里我直接在IDEA里面下载安装了,很方便:

image.png

为了便于自己以后使用 Native Image,这里我直接下载了 GraalVM。

在IDEA中更新项目SDK和模块SDK:

image.png

Maven构建

更新Maven编译配置:

<properties>
  <java.version>17</java.version>
  <maven.compiler.source>${java.version}</maven.compiler.source>
  <maven.compiler.target>${java.version}</maven.compiler.target>
</properties>

Maven重新打包下:

image.png

这一步主要是为了更新下内部组件的 JDK 版本。

启动服务

测试下有没有其他问题,启动所有微服务项目:

image.png

竟然一切正常,也可能与我的项目比较简单有一定的关系,所有服务都成功跑起来了。

更新Dockerfile

原来使用的基础镜像是 java:8-alpine,更新到了亚马逊的openjdk17版本amazoncorretto:17-alpine

# 设置JAVA版本
FROM amazoncorretto:17-alpine
# 指定存储卷, 任何向/tmp写入的信息都不会记录到容器存储层
VOLUME /tmp
# 拷贝运行JAR包
ARG JAR_FILE
ADD ${JAR_FILE} app.jar
# 设置JVM运行参数,限定内存大小,并设置时区为东八区
ENV JAVA_OPTS="\
-server \
-Xms256m \
-Xmx512m \
-XX:MetaspaceSize=256m \
-XX:MaxMetaspaceSize=512m \
-Duser.timezone=GMT+08 "
#空参数,方便创建容器时传参
ENV PARAMS=""
# 入口点, 执行JAVA运行命令
ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /app.jar $PARAMS"]

源代码

看起来没什么问题了,先提交上JDK升级的代码,有需要的同学可以查看提交记录:
build(all): 全量升级到jdk17,更新dockerfile和pom文件。 by stick-i · Pull Request #198 · stick-i/scblogs

升级SpringBoot3.2

为什么选择直接升级到 SpringBoot3.2 而不是 3.0呢?

主要是我开始升级的时候,SpringBoot已经更新到3.2了,而此时的3.0的生命周期已经过半了,目前也还没有推出3.0以上的LTS版本,这么看来我以后总还是要升级的,倒不如现在一起弄了。

image.png

升级pom依赖

跟SpringBoot相关的依赖还是比较多的,尤其是依赖了SpringCore的三方依赖,肯定也是要统一进行升级的。

截至到我写这篇文章的时间,SpringBoot的最新GA版本为 3.2.1:

image.png

我选择相信Spring,直接升级最新版!

image.png

对应的SpringCloud版本为2023.0.0

image.png

其他主要依赖对应升级的情况:

依赖项升级前版本升级后版本备注
SpringBoot2.6.113.2.1目前的最新版,要踩坑就踩最新的坑🤡
SpringCloud2021.0.42023.0.0对应SpringBoot3.2.x
SpringCloudAlibaba2021.0.4.02022.0.0这个库还没出2023的版本,但是2022版也是基于SpringBoot3.0的,应该不会差太多
Mybatis-Plus3.5.3.13.5.5注意:artifactId 从mybatis-plus-boot-starter改成了mybatis-plus-spring-boot3-starter
druid1.2.111.2.20注意:artifactId 从druid-spring-boot-starter改成了druid-spring-boot-3-starter

对了,建议顺便升级下Maven。

解决依赖异常

修改完pom文件之后刷新一下本地依赖包,噢呦,一堆报错:

image.png

我看了一下,就两个问题,分别是 mysql-connector-java 和 javax.servlet-api 这两个包的版本没有被指定,所以Maven找不到对应的包。

为什么没有指定呢?之前也没有指定,但是之前没有报错,说明这两个包之前是有被 spring-boot-starter-parent 所管理的,但是现在它不管了。

image.png

这得去看看SpringBoot3.0的迁移文档:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide

MySQL

在网页里搜索关键字 MySQL,这不就来了:

image.png

就是说 mysql:mysql-connector-java 这个包的坐标改成了 com.mysql:mysql-connector-j,让我们更新的时候也顺带改一下。这个简单,全局搜索然后改一下就好了。

image.png

一改完,版本继承的小图标就出来了,不错不错。

image.png

javax -> jakarta

然后再搜一下关键字 javax,这不就又来了:

image.png

这个就稍微麻烦一点了,不仅Maven坐标从 jakarta.servlet:jakarta.servlet-api 改成了 javax.servlet:javax.servlet-api,而且包名也从 javax.xxx.xxx 改成了 jakarta.xxx.xxx,所有导入了 javax 的包都得改。

先更新下pom文件:

image.png

然后再全局搜索 javax 替换下:

image.png

我试过了,升级完后唯一出现问题的地方就只有一处,但也很容易修改:

image.png

ResponseStatusException 中没有 getStatus() 这个方法了,我使用HttpStatus.valueOf(statusException.getStatusCode().value()) 代替了原来的方法。

做完上面这些后,我的项目已经可以成功编译了,但还不能正常的跑起来。

配置文件属性迁移

SpringBoot3 更改了一些配置属性,例如:spring.redis.host改为了spring.data.redis.host

这一变更几乎对所有项目都会有影响,要查看所有的变更项,可以在官方文档中进行查找:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Configuration-Changelog

但这太silly了,很显然官方也这么认为,所以给开发者提供了一个简单的迁移方法,**引入 **spring-boot-properties-migrator** **,它会帮你自动检测配置文件中需要修改的地方:

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

配置文件属性迁移完毕后,记得删除这里添加的 spring-boot-properties-migrator 依赖。

然后运行项目,当然你的项目大概率是运行不起来的,但别着急,看看你的控制台输出,有没有像我这样的输出内容:

image.png

上面的异常信息其实分为了两个部分,前面部分是需要进行修改的配置:

The use of configuration keys that have been renamed was found in the environment:
Property source ‘bootstrapProperties-default-redis.yaml,DEFAULT_GROUP’:
** Key: spring.redis.host**
** Replacement: spring.data.redis.host**
** Key: spring.redis.password**
** Replacement: spring.data.redis.password**
** Key: spring.redis.port**
** Replacement: spring.data.redis.port**
Each configuration key has been temporarily mapped to its replacement for your convenience. To silence this warning, please update your configuration to use the new keys.

它也给出了重命名之后的key,这里直接对着描述把自己的配置文件改改就好了,比较简单。


后面部分是说有一些配置已经被弃用了,但是它也给出了弃用的原因:

The use of configuration keys that are no longer supported was found in the environment:
Property source ‘bootstrapProperties-default-springmvc.yaml,DEFAULT_GROUP’:
Key: spring.mvc.throw-exception-if-no-handler-found
** Reason: DispatcherServlet property is deprecated for removal and should no longer need to be configured**
Property source ‘bootstrapProperties-default-redis.yaml,DEFAULT_GROUP’:
** Key: spring.redis.lettuce.pool.max-active**
** Reason: none**
** Key: spring.redis.lettuce.pool.max-idle**
** Reason: none**
** Key: spring.redis.lettuce.pool.max-wait**
** Reason: none**
** Key: spring.redis.lettuce.pool.min-idle**
** Reason: none**
Please refer to the release notes or reference guide for potential alternatives.

好吧,这里其实有点小坑,只有上面第一个Key给了弃用原因,说是DispatcherServlet属性已经被移除了。但是后面几个redis相关的Key都是没有给弃用原因的。

既然这样,那我只能自己去官方文档里找了:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Configuration-Changelog

全局搜索下 lettuce.pool,你别说,还真让我找到了:

image.png

明明也没有弃用,就是把redis前面加个data罢了,看来 spring-boot-properties-migrator也偶有瞎说的情况啊。

image.png

再次提醒:配置文件属性迁移完毕后,记得删除之前添加的 spring-boot-properties-migrator 依赖。

ES版本兼容

如果你的es客户端版本和es服务端版本一致(均为8.x),可以直接跳过这部分内容。

项目里使用了 spring-boot-starter-data-elasticsearch,升级SpringBoot3.x 之后,这个依赖的版本也·提高了,对应ES的版本是8.x,而我服务器使用的ES版本是7.x,所以有一些不兼容的问题,启动时出现异常:

image.png

Caused by: java.lang.RuntimeException: node: http://xxxxxx, status: 200, [es/indices.exists] Missing [X-Elastic-Product] header. Please check that you are connecting to an Elasticsearch instance, and that any networking filters are preserving that header.

本来想通过降低 elasticsearch-rest-client 的版本来解决这个问题,但是降低之后又不能兼容 SpringBoot3 了,于是只能另辟蹊径了。

这个说起来比较麻烦,我在 stackoverflow 上找到一篇帖子,里面有对这个问题的描述,可以参考下:https://stackoverflow.com/questions/71142680/co-elastic-clients-transport-transportexception-es-search-missing-x-elastic

image.png

它讲到了两个问题:

  1. 客户端向服务端发送了未知的 Content-Type ,因此其请求被拒绝并返回 406(其实是请求头 compatible-with 不受支持)
  2. 客户端需要验证 response 中是否具有 X-Elastic-Product=Elasticsearch 标头,但服务端并没有返回这个。

问题其实蛮清晰的,但是给出的解决方案让我不太满意,还需要自己重新去构建一个 RestClient,自己读取配置文件然后set进去,又得设置账号密码、又得解析Host的,这我可受不了。

于是经过我的一顿研究之后,我发现了 RestClientBuilderCustomizer 这个类:

image.png

翻译:回调接口,可以由希望通过RestClientBuilder进一步定制RestClient的bean实现,同时保留默认的自动配置。

只要用这个玩意,就可以在原有的 RestClient 基础上,进行一些定制化的操作,比如说解决上面那两个问题。于是乎,我就写了下面这一段代码:

/**
 * Es 兼容性配置,添加响应头,兼容服务端版本
 * <p>
 * 如果客户端与服务端版本一致,可移除此配置。
 *
 * @author 阿杆
 * @version 1.0
 * @date 2024/1/25 22:29
 */
@Component
public class EsCompatibilityConfig implements RestClientBuilderCustomizer {

	@Override
	public void customize(RestClientBuilder builder) {
	}

	@Override
	public void customize(HttpAsyncClientBuilder builder) {
		// 添加响应头,兼容X-Elastic-Product
		HttpResponseInterceptor httpResponseInterceptor =
				(response, context) -> response.addHeader("X-Elastic-Product", "Elasticsearch");
		builder.addInterceptorLast(httpResponseInterceptor);
		// 自定义默认请求头,目的是禁用兼容性请求头 compatible-with
		builder.setDefaultHeaders(List.of(new BasicHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString())));
	}

}

这段代码很简单,在构建 RestClient 的过程中插入了一段代码,修改了请求头和响应头,用来兼容ES版本。只需要把这个类注入到Spring Bean中,就可以被 ElasticsearchRestClientConfigurations 自动加载。

WARN trationDelegate$BeanPostProcessorChecker: is not eligible for getting processed…

如图所示,我的项目在升级到 SpringBoot3.x 后出现了大量的 WARN:

image.png

虽然不影响项目运行,但是看得我很不爽,那只能想想办法看怎么解决掉这个warn了。

随机截取的一段异常信息,其他的也都差不多:

2024-01-28T11:58:45.587+08:00 WARN 1228 — [user-server] [ main] trationDelegate$BeanPostProcessorChecker : Bean ‘org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration’ of type [org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [lbRestClientPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.

注意看上面的异常信息,有任何跟我项目有关的东西吗?没有吧

那有任何跟依赖冲突有关的东西吗?看上去也没有

那这个异常什么时候才开始有的?Spring整体升级之后

好,那既然这样,我们可以大胆的认为这是一个SpringBoot的bug。

image.png

一顿搜索之后,我在github上找到了这个 issue:https://github.com/spring-cloud/spring-cloud-commons/issues/1315

image.png

还真是Spring的bug,不过不是SpringBoot,而是SpringCloud的bug。

image.png

这位大佬也说了,将会在下一个版本(2023.0.1)中修复它,预计2月20日(今天是1月28日),不过他们会先发布新的Commons,用以修复这个bug。

在我看到这个issue的时候,新版的 SpringCloudCommons已经发布了:https://spring.io/blog/2024/01/23/spring-cloud-commons-4-1-1-has-been-released

image.png

于是我对项目中的依赖进行替换,由于这个依赖是从其他Spring-Cloud的组件中自动继承过来的,所以我们只需要在依赖管理里面指定下版本就可以了。

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-commons</artifactId>
      <version>4.1.1</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

添加完之后,果然没有再报warn了,之后等 SpringCloud2023.0.1 发布了,再做一下替换就好了。

image.png

更新自动注入文件

SpringBoot2.7时已经提出使用 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 代替 spring.factories
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.7-Release-Notes#changes-to-auto-configuration

image.png

我升级到 SpringBoot3.2 时,还是支持 spring.factories 的,但再过几个版本可能就不支持了,这边建议直接迁移下,这块几乎没什么成本的。

image.png

源代码

这部分升级的改动有点多,以为已经搞好了,就提PR到main分支了,结果又蹦出来新的问题。

建议需要升级 SpringBoot3.x 的朋友,在看完这篇文章之后,还是再去把官方文档过一遍,看看有没有其他受影响的地方,这样稳妥一点。

代码已提交到GitHub:

  • https://github.com/stick-i/scblogs/pull/200
  • https://github.com/stick-i/scblogs/pull/201
  • https://github.com/stick-i/scblogs/pull/202

源码建议单个 commit 结合 commit message 来查看,这样会更有条理,而不是整个 pr 一起看。

image.png

最后也附上一些我参考到的官方链接:

  • SpringBoot3.0升级指南:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide
  • 3.2发布记录:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.2-Release-Notes
  • 3.0发布记录:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Release-Notes
  • 2.7发布记录:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.7-Release-Notes
  • 3.0配置更新记录:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Configuration-Changelog

后记

本来以为我这小项目简单升级下一两天就弄好了,结果前前后后搞了两周,尤其升级 SpringBoot 的时候,出了一顿问题,踩了不少坑。

看在作者这么认真的份上,建议关注趁早关注下,等我以后火了,在坐的各位就都是老粉了!

454x370.png

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MongoDB数据模型和WiredTiger读写模型

MongoDB数据模型 思考&#xff1a;MongoDB为什么会使用BSON&#xff1f; BSON协议与数据类型 JSON JSON是当今非常通用的一种跨语言Web数据交互格式&#xff0c;属于ECMAScript标准规范的一个子集。JSON&#xff08;JavaScript Object Notation, JS对象简谱&#xff09;即J…

调试OpenHarmony应用/服务

调试流程 DevEco Studio提供了丰富的OpenHarmony应用/服务调试能力&#xff0c;帮助开发者更方便、高效的调试应用/服务。 OpenHarmony应用/服务调试支持使用真机设备调试。使用真机设备进行调试前&#xff0c;需要对HAP进行签名后进行调试。详细的调试流程如下图所示&#x…

node.js与express.js创建项目以及连接数据库

搭建项目 一、技术准备 node版本&#xff1a;16.16.0 二、安装node成功后&#xff0c;安装express,命令如下&#xff1a; npm install -g express 或者&#xff1a; npm install --locationglobal express 再安装express的命令工具&#xff1a; npm install --location…

ASP.NET Core 过滤器 使用依赖项注入

过滤器是 ASP.NET Core 中的特殊组件&#xff0c;允许我们在请求管道的特定阶段控制请求的执行。这些过滤器在中间件执行后以及 MVC 中间件匹配路由并调用特定操作时发挥作用。 简而言之&#xff0c;过滤器提供了一种在操作级别自定义应用程序行为的方法。它们就像检查点&#…

JSP仓储管理系统myeclipse定制开发SQLServer数据库网页模式java编程jdbc

一、源码特点 JSP仓储管理系统系统是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库 &#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为SQLServer2008&#x…

Java关于Excel文件的导入导出

人生如梦 荣华富贵 如木槿之花 朝荣夕逝 需求 导出&#xff1a; 能够将库表内的数据导出多个Excel表&#xff0c;并且生成一个压缩包&#xff0c;提供用户下载导入&#xff1a; 能够将一个压缩包内的多个Excel表解压&#xff0c;并获取表内的所有数据 FileUtils 工具类 publi…

uniapp多格式文件选择(APP,H5)

uniapp多格式文件选择&#xff08;APP&#xff0c;H5&#xff09; 背景实现代码实现运行结果注意事项 尾巴 背景 从手机选择文件进行上传是移动端很常见的需求&#xff0c;在原生开发时由于平台专一性很容易实现。但是用uniapp开发官方提供的API在APP平台只能选择图片和视频&a…

C语言如何理解 c=a,b;?

一、问题 对于表达式 ca,b;和 d(a,b);该如何进⾏理解&#xff1f;它们的值都是怎样的&#xff1f; 二、解答 在C语⾔中&#xff0c;逗号有两个作⽤&#xff0c;⼀是⽤来分隔函数参数&#xff0c;⼆是作为逗号运算符。本题主要考虑的是逗号运算符&#xff0c;根据逗号运算符的规…

第七篇:node中间件详解

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! ​ 目录 &#x1f4d8; 引言&#xff1a; &#…

nacos启动成功,程序连接失败

问题&#xff1a;nacos服务器启动成功后可以访问&#xff0c;但是程序连接却超时 解决&#xff1a;检查端口&#xff0c;2.0以上的版本需要开放的端口一共是三个&#xff01;&#xff01; 8848 9848 9849 找了很久是因为后面两个端口没有开放&#xff0c;原因是因为2.0以上…

控制台的过滤条请求类型被变成下拉选想变成一行

控制台的请求类型被变成下拉选了找到设置---实现----不选Redesign of the filter bar in the Network Panel(重新设计网络面板中的过滤条) 问题如图&#xff1a; 希望是如图&#xff1a; 解决方案:

空间数据分析和空间统计工具库PySAL入门

空间数据分析是指利用地理信息系统(GIS)技术和空间统计学等方法&#xff0c;对空间数据进行处理、分析和可视化&#xff0c;以揭示数据之间的空间关系和趋势性&#xff0c;为决策者提供有效的空间决策支持。空间数据分析已经被广泛运用在城市规划、交通管理、环境保护、农业种植…

Nacos服务注册源码解析

简介&#xff1a;本文将以图文方式详述 Spring Cloud Alibaba 技术体系之 Nacos 服务注册源码解析。 目录 一、Nacos 服务架构 二、Nacos 服务注册流程图&#xff08;源码级别&#xff09; 1. 注册中心核心工作流程 三、Nacos 服务注册源码解析 1. 服务注册 1.1 客户端服…

代码随想录 Leetcode110.平衡二叉树

题目&#xff1a; 代码(首刷看解析 2024年1月30日&#xff09;&#xff1a; class Solution { public:int depth(TreeNode* root) {if (root nullptr) return 0;int leftHeight depth(root->left);if (leftHeight -1) return -1;int rightHeight depth(root->right)…

【Linux C | 网络编程】getsockname 和 getpeername函数详解及C语言例子

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

【遥感专题系列】遥感影像信息提取之——人工目视解译

​遥感影像通过亮度值或像元值的高低差异&#xff08;反映地物的光谱信息&#xff09;及空间变化&#xff08;反映地物的空间信息&#xff09;来表示不同地物的差异&#xff0c;这是区分不同影像地物的物理基础。 ​人工解译是目前国内使用最多的一种影像提取方法&#xff0c;如…

Android studio环境搭建过程异常

异常&#xff1a;Connect timed out 创建新项目时&#xff0c;提示time out 解决方案&#xff1a;修改gradle下载地址&#xff0c;使用国内镜像地址 distributionUrlhttps\://services.gradle.org/distributions/gradle-8.2-bin.zip修改成distributionUrlhttps\://mirrors.c…

海外拓展必备:精细规划的出海策略,实现市场全球化的第一步

随着全球化的深入&#xff0c;越来越多的企业开始将目光投向海外市场&#xff0c;以寻求更广阔的发展空间。然而&#xff0c;进入新的市场并进行有效的海外营销并非易事&#xff0c;需要经过精心策划和系统性的执行。本文Nox聚星将和大家详细探讨出海营销的第一步应该如何着手&…

初始化和赋值

列表初始化 #include <iostream>struct test{int a; };class object{ public:object(int v10):a{v}{}int a; };int main(){test t1;test t2{};std::cout<<t1.a<<std::endl;std::cout<<t2.a<<std::endl;object b2{11};std::cout<<b2.a<…