当谈到从Spring Boot 1.5升级至2.1时的经历
首先
由于Spring Boot 1.x系列将于2019年8月1日结束维护,因此我迫不得已将Spring Boot版本从1.5.2升级到2.1.5。以下是我在升级过程中所做的笔记。
主要的构成
-
- Java 8
-
- Gradle 4.10.3
-
- Web、バッチ両方ありの巨大なマルチプロジェクト
Springアプリケーション5個
プレーンなJavaアプリケーション1個
ライブラリ系のモジュール6個
MySQL
Flyway
JOOQ
Thymeleaf
做过的事情 (zuò guò de shì
收集情报
↓的公式迁移指南中记录了基本的迁移方法和注意事项。
Spring Boot 2.0 迁移指南
在操作过程中,我一边阅读公式迁移指南,一边通过搜索解决了一些不明确或遇到困难的问题。此外,对于主要库的重要版本更改,我会查看发布说明,以确保没有破坏性改动。
1. 首先将spring-boot-properties-migrator添加到项目依赖中(*在迁移完成后移除*)。
在Spring Boot 2中,一些在application.properties/application.yml中定义的属性的键和配置内容已经发生了变化。
如果将spring-boot-properties-migrator添加到依赖项中,那么在应用启动时,如果存在配置内容仍然保持旧状态的属性,它会生成警告日志。同时,它还会暂时允许使用旧属性的写法来确保应用的正常运行。
在dependencies中添加以下行。(完成迁移后删除)。
runtime "org.springframework.boot:spring-boot-properties-migrator"
2. 添加Gradle的依赖管理插件。
在1.x版本中,Spring Boot插件中包含了Dependency Management插件,但从2.x版本开始,Dependency Management插件似乎已经分离出来
在build.gradle文件中添加Dependency Management插件。
apply plugin: 'org.springframework.boot'
+ apply plugin: 'io.spring.dependency-management' // <-- コレを追加
将Spring Boot的版本升级
etx {
- springBootVersion = '1.5.2.RELEASE'
+ springBootVersion = '2.1.5.RELEASE'
}
升级Spring Boot版本会自动升级各种库的版本。
这次的主要变化
-
- Spring (4→5)
-
- Thymeleaf (2→3)
-
- MySQLのJDBCドライバー (5.1→8.0)
-
- Flyway (4→5)
- JOOQ (3.9→3.11)
此外,RDB的连接池库已从Tomcat JDBC更换至HikariCP。
※ 每个库的具体版本号可以在spring-boot-dependencies的POM文件中找到。
4. Spring Boot的配置
4.1. Gradle配置
bootRepackage这个任务消失了,换成了名为bootJar的任务。
bootJar {
mainClassName = 'foo.bar.App'
launchScript() // <-- bootRapackageで`executable = true`を設定していた場合、これがその代わりになる
}
修正绑定属性时的键名。
如果在Java中使用@ConfigurationProperties 或者@Value将Spring Boot的属性绑定到Java中,需要统一属性名称的写法为“Canonical”。详细请参考Spring Boot 2.0 Canonical Properties。
基本上,全部改成小写字母,删除”-“和”_”就可以了。
- @ConfigurationProperties(prefix = "foo-bar.apiKey")
+ @ConfigurationProperties(prefix = "foobar.apikey")
5. 春季网络MVC
5.1. WebMvcConfigurerAdapter转变为WebMvcConfigurer.
WebMvcConfigurerAdapter类已被废弃,已改为使用WebMvcConfigurer接口。
- public class WebMvcConfig extends WebMvcConfigurerAdapter {
+ public class WebMvcConfig implements WebMvcConfigurer {
5.2版本的控制器无法自动映射带有文件扩展名的URL。
@GetMapping("/users")
public List<Users> listUsers() {
我们之前准备了类似的端点,并且前端通过”GET /users.json”的路径进行访问。但是现在不能这样做了。
现在只需要普通地通过”GET /users”进行访问即可,所以我将”.json”全部删除了。
6. MySQL
5.1变为8.0。
6.1. 修改MySQL驱动器的类名。
我找到了com.mysql.jdbc.Driver的部分,并将其替换为com.mysql.cj.jdbc.Driver。
7. JOOQ 只需要一个选项, 请用中文将以下内容改述一遍:
3.9→3.11表示正在进行中。
由于jOOQ版本更新,进行了一些修正。
建议阅读jOOQ发布说明历史中的Breaking changes部分。
升级JOOG的Gradle插件版本为7.1。
从JOOQ3.11.x版本开始,需要使用gradle-jooq-plugin3.x插件。
plugins {
- id 'nu.studer.jooq' version '2.0.11'
+ id 'nu.studer.jooq' version '3.0.3'
}
7.2. 修正Gradle设置以生成JOOQ代码
由于API包的名称已更改,因此需要进行修正。
mainDb(sourceSets.main) {
jdbc {
...
}
generator {
- name = 'org.jooq.util.DefaultGenerator'
+ name = 'org.jooq.codegen.DefaultGenerator'
...
database {
- name = 'org.jooq.util.mysql.MySQLDatabase'
+ name = 'org.jooq.meta.mysql.MySQLDatabase'
...
重新生成JOQQ
Alternatively:
重新生成JOQQ的生成
重新生成代码
由于7.4版本中Cursor#fetchOne()方法被标记为不推荐使用,所以需要进行修正。
while (cursor.hasNext())
- Record record = cursor.fetchOne();
+ Record record = cursor.fetchNext();
8. 飞行之路 zhī lù)
如果从3系转移到5系,则需要先转移到4系。
8.1. 更改属性名称
application.properties / application.yml 的属性名称已经从 flyway.* 变为 spring.flyway.*。
- flyway:
- enabled: true
+ spring:
+ flyway:
+ enabled: true
设定迁移执行历史管理表的名称。
在Flyway的3系和4系中,执行历史记录通过一个名为schema_version的表进行管理。然而,在5系中,该表的名字改为了flyway_schema_history。如果要继续使用schema_version表,需要在application.properties或application.yml文件中设置一个名为spring.flyway.table的属性。
spring:
flyway:
table: schema_version
此外,如果您正在使用Gradle的Flyway插件,也需要在那里进行相应配置。
flyway {
...
table = 'schema_version'
}
9. Thymeleaf: 西洋芹
9.1.修复依赖库
- implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity4'
+ implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' // <--- Spring SecurityのDialectのバージョンアップ
修正模板布局的描述方法
Thymeleaf3 的布局语法发生了变化。
参考:
-
- https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guide#template-engines
- https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#template-layout
受限于时间和空间的限制,我们只需要一种选择,原句表述如下:
排版
<!DOCTYPE html>
<html lang="ja"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="utf-8"/>
<!-- 「{各ページのタイトル} | アプリ名」のようなtitleになる -->
- <title layout:title-pattern="$CONTENT_TITLE | $DECORATOR_TITLE">アプリ名</title>
+ <title layout:title-pattern="$CONTENT_TITLE | $LAYOUT_TITLE">アプリ名</title>
...
</head>
<body>
<!-- 共通のHTMLを埋め込む -->
- <div layout:replace="common/header::partial"></div>
+ <div layout:replace="~{common/header::partial}"></div>
<!-- 各ページのコンテンツをここに展開 -->
<div layout:fragment="content"></div>
</bod>
</html>
单独页面
<!DOCTYPE html>
<html
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:th="http://www.springframework.org/schema/mvc"
- layout:decorator="layout/default">
+ layout:decorate="~{layout/default}">
<head>
<title>各ページのタイトル</title>
</head>
<body>
<!-- 各ページのコンテンツ -->
<div layout:fragment="content">
Hello World
</div>
</body>
</html>
10. 连接池
由于Tomcat JDBC已更改为HikariCP,因此需要修改配置内容。
属性名称将从spring.datasource.tomcat.*更改为spring.datasource.hikari.*。
HikariCP可以通过com.zaxxer.hikari.HikariConfig中的定义进行配置。
故障排除
生成Jar文件时不包含前端构建内容
最初就在Gradle中定义了用于构建前端的任务,并设置在创建jar文件时执行。
jar.dependsOn compileFrontend
但是,从Spring Boot 2版本开始,我们开始使用bootJar任务来生成jar包,所以进行了如下修改。
bootJar.dependsOn compileFrontend
DBUnit在MySQL上崩溃了。
org.dbunit.database.AmbiguousTableNameException: ACCOUNTS
当多个数据库中存在同名表时,似乎会出现错误。当在JDBC的URL中添加了nullCatalogMeansCurrent=true查询参数后,问题得到解决。(这似乎是MySQL的JDBC驱动程序的默认行为发生了变化)
当使用JOOQ对TINYINT(1)字段进行SELECT时会出错。
java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.lang.Byte
在使用JOOb进行开发时,我们的策略是将BIT(1)映射为Boolean,而将TINYINT(1)映射为Byte。然而,在更新到Spring Boot 2之后,TINYINT(1)被错误地映射为Boolean,导致了ClassCastException的发生。
当我在JDBC的URL中添加了查询参数”tinyInt1isBit=false”后问题得到解决。
据说MySQL的JDBC驱动在内部将TINYINT(1)作为BIT(1)处理,导致其变成了布尔类型。
如果一个WEB域名中包含下划线(_),则会出现IllegalArgumentException异常。
java.lang.IllegalArgumentException: The character [_] is never valid in a domain name.
Tomcat的版本升级后,似乎无法接受包含“_”的域名。
(根据RFC的规定,域名中包含“_”是不正确的。)
→由于子域名中包含“_”,所以我们更改了子域名以进行适应。
请参考以下链接:https://stackoverflow.com/questions/53504857/在域名中,该字符永远无效。