使用Kotlin和Spring Boot 2.0实现一个简单的Rest API
总结
這篇文章是關於使用Kotlin with Spring Boot 1.5來實現簡單的Rest API的,但這是Spring Boot 2.0版本的文章。我們使用目前最新版本的RC2(2018/2)來進行實作。
-
- 2018/3/1にSpring Boot 2.0.0 GAがリリースされました。(Spring Boot 2.0 goes GA)
- 2018/5/9にSpring Boot 2.0.2がリリースされましたのでソースコードおよび記事を修正しました。(Spring Boot 2.0.2)
源代码位于rubytomato/demo-kotlin-spring2。
环境
-
- Windows 10 Professional
-
- Java 1.8.0_172
-
- Kotlin 1.2.31
-
- Spring Boot 2.0.2
Spring Framework 5.0.5
MySQL 5.7.19
Gradle 4.5.1
IntelliJ IDEA 2017.3
请参考。
-
- Spring Boot 2.0 Release Notes
- Spring Boot with Java 9 and above
如果要进行1.5版本的迁移
已经准备好了Spring Boot 2.0迁移指南。
应用程序 xù)
应用程序的模板是通过Spring Initializr生成的。
生成的build.gradle文件中指定了Kotlin版本为1.2.20,但是Spring Boot 2.0.0支持的版本可达到1.2.21,因此在这篇文章中我们使用了1.2.21版本。
构建.gradle
buildscript {
ext {
kotlinVersion = "1.2.31"
springBootVersion = "2.0.2.RELEASE"
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-noarg:${kotlinVersion}")
}
}
apply plugin: "kotlin"
apply plugin: "kotlin-spring"
apply plugin: "kotlin-jpa"
apply plugin: "org.springframework.boot"
apply plugin: "io.spring.dependency-management"
apply plugin: "kotlin-kapt"
group = "com.example"
version = "0.0.3-SNAPSHOT"
sourceCompatibility = 1.8
targetCompatibility = 1.8
compileKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "1.8"
}
}
compileTestKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "1.8"
}
}
compileJava {
options.compilerArgs << "-Xlint:unchecked,deprecation"
}
compileTestJava {
options.compilerArgs << "-Xlint:unchecked,deprecation"
}
repositories {
mavenCentral()
}
dependencies {
// for web
compile("org.springframework.boot:spring-boot-starter-web")
compile("com.fasterxml.jackson.module:jackson-module-kotlin")
// for db
compile("org.springframework.boot:spring-boot-starter-data-jpa")
runtime("mysql:mysql-connector-java")
// compile("javax.xml.bind:jaxb-api:2.1")
// kotlin
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
compile("org.jetbrains.kotlin:kotlin-reflect")
// for dev
kapt("org.springframework.boot:spring-boot-configuration-processor")
runtime("org.springframework.boot:spring-boot-devtools")
compileOnly("org.springframework.boot:spring-boot-configuration-processor")
// for test
testCompile("org.springframework.boot:spring-boot-starter-test")
testCompile("com.h2database:h2")
}
-Xjsr305编译器标志
在使用Spring Initializr生成的项目中,默认情况下会启用严格模式。
在严格模式下,如果Java端的对象字段上有Nullable注解,则在Kotlin端不将其视为Nullable将导致编译错误。
例如,以下代码中的result.body.id处将会导致编译错误。(在非严格模式下不会产生编译错误,但会产生警告。)
@Test
fun `test get`() {
val result: ResponseEntity<Memo> = testRestTemplate.getForEntity("/memo/1", Memo::class.java)
assertThat(result.body.id).isEqualTo(1L)
// Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Memo? :compileTestKotlin FAILED
}
这是因为body字段上有一个Nullable注解。
public class HttpEntity<T> {
@Nullable
private final T body;
}
为了通过编译,需要将Nullable参数进行如下处理。
assertThat(result.body?.id).isEqualTo(1L)
// もしくはresult.body!!.id
管理依赖性
我们需要使用插件io.spring.dependency-management来进行依赖管理。
`javax.xml.bind` 组件
在Java9时候会需要注释掉的javax.xml.bind:jaxb-api依赖。原因可以参考https://github.com/spring-projects/spring-boot/issues/11205。
json -> JSON
从2.0版本开始,已经提供了一个名为spring-boot-starter-json的用于处理json的starter。它已经包含在spring-boot-starter-web的依赖关系中,因此不需要额外指定。但是在Kotlin中,还需要添加com.fasterxml.jackson.module:jackson-module-kotlin作为依赖。
应用程序配置文件.yml
spring:
application:
name: kotlin with spring-boot 2.0
output:
ansi:
enabled: detect
profiles:
active: dev
datasource:
url: jdbc:mysql://localhost:3306/demo_db?useSSL=false
username: demo_user
password: demo_pass
hikari:
connection-test-query: select 1
connection-timeout: 10000
maximum-pool-size: 2
minimum-idle: 2
jpa:
open-in-view: true
properties:
hibernate:
show_sql: true
format_sql: true
use_sql_comments: true
generate_statistics: true
jackson:
serialization:
write-dates-as-timestamps: false
write-durations-as-timestamps: true
server:
servlet:
context-path: /app
port: 9000
logging.file: demo.log
logging:
file:
max-size: 50MB
max-history: 10
level:
root: info
org.springframework: info
org.hibernate: info
org.hibernate.SQL: debug
com.example.demo: debug
从2.0版本开始,默认的数据源已经改为HikariCP。
要设置HikariCP的属性,请指定为spring.datasource.hikari.*。
此外,由于已经对命名空间进行了更改,因此准备了支持从1.5版本迁移的模块。使用只需将以下模块集成即可。一旦集成,如果需要修改的属性存在,将在控制台显示警告,并临时将其转换为新属性以便启动。
Maven – 专家,行家
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
</dependency>
Gradle:工具
runtime("org.springframework.boot:spring-boot-properties-migrator")
应用程序的启动类
从2.0版本起,引入了一个名为runApplication的函数。
package com.example.demokotlin2
@SpringBootApplication
class DemoKotlin2Application
fun main(args: Array<String>) {
runApplication<DemoKotlin2Application>(*args)
}
实体和仓库
由于Spring Data Jpa的版本升级,仓库有一些轻微的更改。
实体
從1.5版本起,並無任何更改。
package com.example.demokotlin2.entity
import java.io.Serializable
import java.time.LocalDateTime
import javax.persistence.*
@Entity
@Table(name = "memo")
data class Memo(
@Column(name = "title", nullable = false)
var title: String,
@Column(name = "description", nullable = false)
var description: String,
@Column(name = "done", nullable = false)
var done: Boolean = false,
@Column(name = "updated", nullable = false)
var updated: LocalDateTime = LocalDateTime.now(),
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0
) : Serializable
代码库
在这个例子中,我们实现了JpaRepository接口,但是由于该接口中定义的方法签名有一些变化,所以在从1.5版本迁移时可能需要修改代码。
package com.example.demokotlin2.repository
import com.example.demokotlin2.entity.Memo
import org.springframework.data.jpa.repository.JpaRepository
interface MemoRepository : JpaRepository<Memo, Long>
- シグネチャの変更点は補足欄にまとめてあります。
服务
与1.5版本相比,没有什么值得特别注意的变化。
package com.example.demokotlin2.service
import com.example.demokotlin2.entity.Memo
import org.springframework.data.domain.Pageable
interface MemoService {
fun findById(id: Long): Memo?
fun findAll(page: Pageable): List<Memo>
fun store(memo: Memo)
fun removeById(id: Long)
}
package com.example.demokotlin2.service.impl
import com.example.demokotlin2.entity.Memo
import com.example.demokotlin2.repository.MemoRepository
import com.example.demokotlin2.service.MemoService
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
@Service
class MemoServiceImpl(
private val repository: MemoRepository) : MemoService {
@Transactional(readOnly = true)
override fun findById(id: Long): Memo? {
return repository.findById(id).orElseGet(null)
}
@Transactional(readOnly = true)
override fun findAll(page: Pageable): List<Memo> {
return repository.findAll(page).content
}
@Transactional(timeout = 10)
override fun store(memo: Memo) {
repository.save(memo)
}
@Transactional(timeout = 10)
override fun removeById(id: Long) {
repository.deleteById(id)
}
}
控制器 qì)
与1.5相比,并无值得特别注意的变化。
package com.example.demokotlin2.controller
import com.example.demokotlin2.entity.Memo
import com.example.demokotlin2.service.MemoService
import org.springframework.data.domain.Pageable
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
@RestController
@RequestMapping(path = ["memo"])
class MemoController(
private val service: MemoService) {
@GetMapping(path = ["{id}"], produces = [MediaType.APPLICATION_JSON_UTF8_VALUE])
fun id(@PathVariable(value = "id") id: Long): ResponseEntity<Memo> {
val memo = service.findById(id)
return if (memo != null) {
ResponseEntity.ok(memo)
} else {
ResponseEntity(HttpStatus.NOT_FOUND)
}
}
@GetMapping(path = ["list"], produces = [MediaType.APPLICATION_JSON_UTF8_VALUE])
fun list(page: Pageable): ResponseEntity<List<Memo>> {
return ResponseEntity.ok(service.findAll(page))
}
@PostMapping(produces = [MediaType.TEXT_PLAIN_VALUE], consumes = [MediaType.APPLICATION_JSON_UTF8_VALUE])
fun store(@RequestBody memo: Memo): ResponseEntity<String> {
service.store(memo)
return ResponseEntity.ok("success")
}
@DeleteMapping(path = ["{id}"], produces = [MediaType.TEXT_PLAIN_VALUE])
fun remove(@PathVariable(value = "id") id: Long): ResponseEntity<String> {
service.removeById(id)
return ResponseEntity.ok("success")
}
}
- ページング、ソートの設定をカスタマイズできるプロパティが追加されています。
spring.data.web.pageable.*
spring.data.web.sort.*
例如,您可以使用以下属性来设置每页显示的最大数量。
spring.data.web.pageable.default-page-size= 10
验证API的运作
搜索
> curl -v http://localhost:9000/app/memo/1
> curl -v http://localhost:9000/app/memo/list
翻页
> curl -v http://localhost:9000/app/memo/list?page=0&size=10
注册新用户
> curl -v -H "Content-Type:application/json" -d @memo.json -X POST http://localhost:9000/app/memo
删除
> curl -v -X DELETE http://localhost:9000/app/memo/1
考试代码
仓库的单元测试
package com.example.demokotlin2.repository
import com.example.demokotlin2.entity.Memo
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
import org.springframework.test.context.junit4.SpringRunner
import org.assertj.core.api.Assertions.*
import org.springframework.test.context.jdbc.Sql
import java.time.LocalDateTime
@RunWith(SpringRunner::class)
@DataJpaTest
class MemoRepositoryTests {
@Autowired
lateinit var entityManager: TestEntityManager
@Autowired
lateinit var sut: MemoRepository
@Test
@Sql(statements = ["INSERT INTO memo (id, title, description, done, updated) VALUES (1, 'memo test', 'memo description', FALSE, CURRENT_TIMESTAMP)"])
fun findById() {
val expected = entityManager.find(Memo::class.java, 1L)
val actual = sut.findById(expected.id).orElseGet { null }
assertThat(actual).isNotNull()
assertThat(actual).isEqualTo(expected)
}
@Test
fun save() {
val updated = LocalDateTime.of(2018, 2, 19, 18, 12, 0)
val expected = Memo(title = "test title", description = "test description", done = true, updated = updated)
sut.saveAndFlush(expected)
val actual = entityManager.find(Memo::class.java, expected.id)
assertThat(actual).isEqualTo(expected)
}
@Test
@Sql(statements = ["INSERT INTO memo (id, title, description, done, updated) VALUES (1, 'memo test', 'memo description', FALSE, CURRENT_TIMESTAMP)"])
fun delete() {
val expected = entityManager.find(Memo::class.java, 1L)
sut.deleteById(expected.id)
sut.flush()
val actual = entityManager.find(Memo::class.java, expected.id)
assertThat(actual).isNull()
}
}
服务的单元测试
package com.example.demokotlin2.service
import com.example.demokotlin2.entity.Memo
import com.example.demokotlin2.repository.MemoRepository
import com.example.demokotlin2.service.impl.MemoServiceImpl
import org.junit.*
import org.mockito.*
import org.mockito.Mockito.*
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
import org.mockito.quality.Strictness
import org.assertj.core.api.Assertions.*
import org.springframework.data.domain.PageImpl
import org.springframework.data.domain.PageRequest
import java.util.*
class MemoServiceImplTests {
@Rule
@JvmField
val rule: MockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS)
@Mock
lateinit var repository: MemoRepository
@InjectMocks
lateinit var sut: MemoServiceImpl
@Test
fun findById() {
val expected = Optional.ofNullable(Memo(id = 11, title = "title", description = "description", done = true))
Mockito.`when`(repository.findById(anyLong())).thenReturn(expected)
val actual = sut.findById(11)
assertThat(actual).isNotNull()
assertThat(actual).isEqualTo(expected.get())
verify(repository, times(1)).findById(anyLong())
}
@Test
fun findAllWithEmptyList() {
val pageable: PageRequest = PageRequest.of(0, 5)
val expected = emptyList<Memo>()
val page = PageImpl<Memo>(expected, pageable, 0)
Mockito.`when`(repository.findAll(eq(pageable))).thenReturn(page)
val actual = sut.findAll(pageable)
assertThat(actual).hasSize(0)
verify(repository, times(1)).findAll(eq(pageable))
}
@Test
fun findAll() {
val pageable: PageRequest = PageRequest.of(0, 5)
val expected = listOf(
Memo(id = 1, title = "title A", description = "desc A", done = true),
Memo(id = 2, title = "title B", description = "desc B", done = false),
Memo(id = 3, title = "title C", description = "desc C", done = true)
)
val page = PageImpl<Memo>(expected, pageable, 3)
Mockito.`when`(repository.findAll(eq(pageable))).thenReturn(page)
val actual = sut.findAll(pageable)
assertThat(actual).hasSize(3)
assertThat(actual).containsSequence(expected)
verify(repository, times(1)).findAll(eq(pageable))
}
}
控制器的测试
单体
package com.example.demokotlin2.controller
import com.example.demokotlin2.entity.Memo
import com.example.demokotlin2.service.MemoService
import com.fasterxml.jackson.databind.ObjectMapper
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Mockito
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.http.MediaType
import org.springframework.test.context.junit4.SpringRunner
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.*
import org.springframework.test.web.servlet.result.MockMvcResultHandlers.print
import java.nio.charset.Charset
@RunWith(SpringRunner::class)
@WebMvcTest(MemoController::class)
class MemoControllerTests {
@Autowired
lateinit var mvc: MockMvc
@Autowired
lateinit var objectMapper: ObjectMapper
@MockBean
lateinit var memoService: MemoService
private val contentType = MediaType(MediaType.APPLICATION_JSON.type,
MediaType.APPLICATION_JSON.subtype, Charset.forName("utf8"))
@Test
fun getOne() {
val expected = Memo(id=1L, title="test title", description="test description", done=true)
val expectedJson = objectMapper.writeValueAsString(expected)
Mockito.`when`(memoService.findById(anyLong())).thenReturn(expected)
val builder = MockMvcRequestBuilders.get("/memo/{id}", 1)
.accept(MediaType.APPLICATION_JSON_UTF8)
val result = mvc.perform(builder)
.andExpect(status().isOk)
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$").isNotEmpty)
.andExpect(jsonPath("$.title").value(expected.title))
.andExpect(jsonPath("$.description").value(expected.description))
.andExpect(jsonPath("$.done").value(expected.done))
.andDo(`print`())
.andReturn()
assertThat(result.response.contentAsString).isEqualTo(expectedJson)
}
}
融合
package com.example.demokotlin2.controller
import com.example.demokotlin2.DemoKotlin2Application
import com.example.demokotlin2.entity.Memo
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.test.context.junit4.SpringRunner
import org.assertj.core.api.Assertions.*
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
@RunWith(SpringRunner::class)
@SpringBootTest(classes = [DemoKotlin2Application::class],
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class MemoControllerTests {
class MemoList : MutableList<Memo> by ArrayList()
@Autowired
lateinit var testRestTemplate: TestRestTemplate
@Test
fun getOne() {
val result = testRestTemplate.getForEntity("/memo/1", Memo::class.java)
assertThat(result).isNotNull
assertThat(result.statusCode).isEqualTo(HttpStatus.OK)
assertThat(result.headers.contentType).isEqualTo(MediaType.APPLICATION_JSON_UTF8)
assertThat(result.body?.id).isEqualTo(1L)
}
@Test
fun pagination() {
val result = testRestTemplate.getForEntity("/memo/list?page={page}&size={size}", MemoList::class.java, 0, 3)
assertThat(result).isNotNull
assertThat(result.statusCode).isEqualTo(HttpStatus.OK)
assertThat(result.headers.contentType).isEqualTo(MediaType.APPLICATION_JSON_UTF8)
assertThat(result.body).hasSize(3)
}
}
补充
M1至M7、RC1和RC2的发布说明
我大致总结了从M1到RC2的发布说明的内容。(2018年2月19日)
但是,由于时间上的限制,我无法检查和验证所有内容,所以我只挑选了个人感兴趣和似乎影响较大的部分。
Spring-Boot-2.0.0-M1-发布说明
- Spring Boot 2.0.0 M1 Configuration Changelog
★基线的修改
-
- Java8 or laterが必要です。
- Java6,7はサポートされません。
★更改主要依赖版本








5.1.0mockito1.10.192.15.0




1.2.21
轻松绑定
- Spring Boot Configuration Binding
继续优化了属性的宽松绑定(Relaxed binding),具体信息可以在Relaxed Binding 2.0中找到。
属性描述方法
在属性的表示方法中有以下选项。
kebab-caseperson.first-name.propertiesと.ymlファイルでの使用を推奨snake-caseperson.first_namekebab-caseの代替upper-casePERSON_FIRSTNAMEシステム環境変数を使用する場合に推奨
属性可以根据(1)前缀和(2)名称进行区分,前缀和名称的使用语法是不同的。
my-app.my-module.foo.first-name= ruby
^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^
| | |
(1) (2) (3)
-
- 前缀:连字符命名法
-
- 名称:连字符命名法、驼峰命名法、蛇形命名法
- 值:プロパティ的值
从2.0版本开始,ConfigurationProperties注解的prefix属性的用法发生了变化。
例如,为了绑定以下属性
my-app.my-module.foo.first-name= ruby
my-app.my-module.foo.last-name= tomato
my-app.my-module.foo.age= 10
可以使用kebab-case(“my-app.my-module.foo”)作为前缀进行描述,
@Component
@ConfigurationProperties(prefix = "my-app.my-module.foo")
data class FooConfig(
var firstName: String = "",
var lastName: String = "",
var age: Int = 0
)
使用snake-case(“my_app.my_module.foo”)或camel-case(“myApp.myModule.foo”)来编写代码,在运行时会抛出异常。
在1.5版本之前,使用这些写法不会引发异常,但由于属性的写法不统一,无法按预期进行绑定。
Caused by: org.springframework.boot.context.properties.source.InvalidConfigurationPropertyNameException: Configuration property name 'my_app.my_module.foo' is not valid
在设置属性的一侧,以下语法都可以进行绑定。
my-app.my-module.foo.first-name= ruby
my_app.my_module.foo.first_name= ruby
myApp.myModule.foo.firstName= ruby
操作系统环境变量
> SET MY_APP_MY_MODULE_FOO_FIRST_NAME= ruby
如果记法混杂的话
my-app.my-module.foo.first_name= ruby
my-app.my-module.foo.firstName= ruby
my-app.my-module.foo.FIRST_NAME= ruby
只需一种选项:
ConditionalOnProperty注解的prefix和name属性也应使用kebab-case来描述。
但需要注意的是,即使使用snake-case或camel-case进行描述也不会引发异常。
@ConditionalOnProperty(prefix = "my-app.my-module.foo", name = ["test-flag"])
顺便说一句,如果想要在属性具有特定的值时进行绑定,可以使用havingValue来指定条件。
在这个例子中,当”my-app.my-module.foo.test-flag= true”时,BarProperties的对象将被注册到DI容器中。
@Bean
@ConditionalOnProperty(prefix = "my-app.my-module.foo", name = ["test-flag"], havingValue = "true")
fun bar(foo: FooProperties): BarProperties {
return BarProperties(foo.name)
}
data class BarProperties(val name: String)
此外,绑定API已进行了以下修改。
除外
属性中存在着一些用于传递给Spring使用的而非内置库的属性定义。
比如下面的spring.jpa.properties.hibernate.*就是个例子,若不按规定的语法来书写,将无法被识别。
以这个例子来说,name部分(show_sql)必须使用蛇形命名才能被识别。
spring.jpa.properties.hibernate.show_sql= true
特性移除
-
- Remote CRaSH shell
-
- Spring Loaded
- Spring Boot CLIからテスト機能
更改嵌入式容器的软件包
码头
JettyReactiveWebServerFactory
Tomcat 翻译成中文就是猫头鹰。
TomcatReactiveWebServerFactory
被水流带走
UndertowReactiveWebServerFactory
Netty(補充)
- Nettyは2.0から追加されたWebFluxのデフォルトのengineです。
★更改默认的数据源
默认的数据源已从Tomcat更改为HikariCP。
HikariCP 光华连接池
如果明确指定的话
由于默认设置,不需要明确指定,但是如果要写的话,可以按照以下方式来写。
spring.datasource.type= com.zaxxer.hikari.HikariDataSource
HikariCP的属性设置
spring.datasource.hikari.*
data-source-propertiesMap
driver-class-nameStringnonehealth-check-propertiesMap
health-check-registryObjectnone (HikariCP 2.3.2+ supports Dropwizard HealthChecks.)idle-timeoutLong600000 msinitialization-fail-timeoutLong1 sisolate-internal-queriesBooleanfalsejdbc-urlStringnoneleak-detection-thresholdLong0 mslogin-timeoutInteger(officialに記載なし)max-lifetimeLong1800000 msmaximum-pool-sizeInteger10metric-registryObjectnonemetrics-tracker-factoryFactory(officialに記載なし)minimum-idleIntegersame as maximumPoolSizepasswordStringnonepool-nameStringauto-generatedread-onlyBooleanfalseregister-mbeansBooleanfalsescheduled-executorservicenoneschemaStringdriver defaulttransaction-isolationStringdriver defaultusernameStringnonevalidation-timeoutLong5000ms
汤姆猫
如果想要恢复到Tomcat的话
Maven (一种工具)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</dependency>
Gradle (格雷德)
compile("org.springframework.boot:spring-boot-starter-data-jpa") {
exclude group: "com.zaxxer", module: "HikariCP"
}
compile("org.apache.tomcat:tomcat-jdbc")
覆盖默认设置。
spring.datasource.type= org.apache.tomcat.jdbc.pool.DataSource
Tomcat连接池的属性设置
spring.datasource.tomcat.*
常见的特点
defaultTransactionIsolationStringJDBC driver defaultdefaultCatalogString
driverClassNameString
usernameString
passwordString
maxActiveint100maxIdleintsame as maxActiveminIdleintsame as initialSizeinitialSizeint10maxWaitint30000 mstestOnBorrowbooleanfalsetestOnConnectbooleanfalsetestOnReturnbooleanfalsetestWhileIdlebooleanfalsevalidationQueryString
validationQueryTimeoutint-1validatorClassNameStringnulltimeBetweenEvictionRunsMillisint5000 msnumTestsPerEvictionRunint*Property not usedminEvictableIdleTimeMillisint60000 msaccessToUnderlyingConnectionAllowedboolean
removeAbandonedbooleanfalseremoveAbandonedTimeoutint60 slogAbandonedbooleanfalseconnectionPropertiesStringnullpoolPreparedStatementsboolean*Property not usedmaxOpenPreparedStatementsint*Property not used
- Tomcat JDBC Enhanced Attributesは割愛します。
删除对spring-boot-starter-web的依赖。
-
- spring-boot-starter-mustache
- spring-boot-starter-thymeleaf
这些starter的依赖关系已从spring-boot-starter-web中删除。
具体而言,pom.xml文件中的依赖关系已被删除。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
WebFlux的支持
-
- spring-boot-starter-webflux
- spring-boot-starter-reactor-netty (default web engine)
对于响应式数据的支持
新增了一种能够进行反应性处理的数据存储库。
-
- MongoDB (spring-boot-starter-data-mongodb-reactive)
-
- Redis (spring-boot-starter-data-redis-reactive)
- Cassandra (spring-boot-starter-data-cassandra-reactive)
代理策略的默认更改
默认值已更改为CGLIB。您可以通过更改proxy-target-class属性进行设置。
spring.aop.proxy-target-class= true
-
- true : CGLIB subclass-based
- false : JDK interface-based
更改application.properties的命名空间
Servlet的特定服务器属性
多部分配置
更改webEnvironment标志的指定方法
由于添加了WebFlux,新增了一个名为spring.main.web-application-type的新属性。
在Spring Boot 1.5之前的版本中,如果不想将其作为web应用程序启动(即不启动内嵌的web容器),可以进行以下配置。
spring.main.web-environment= false
从2.0版本开始,可以通过设置新的属性spring.main.web-application-type为none来指定。
spring.main.web-application-type= none
这个属性可以指定的值有三种类型。
-
- none
The application should not run as a web application and should not start an embedded web server
servlet
The application should run as a servlet-based web application and should start an embedded servlet web server.
reactive
The application should run as a reactive web application and should start an embedded reactive web server.
更改Mustache模板的默认值
Mustache模板引擎的模板文件默认扩展名已从.html更改为.mustache。
spring.mustache.suffix= .mustache
★ Gradle插件的变更
正如这篇博客(Spring Boot的新Gradle插件)所发布的那样,Gradle插件的功能已经发生了变化。
生成可以运行的jar/war文件
生成可执行的JAR或WAR文件,通常使用bootRepackage任务来完成,但现在已被替换为bootJar或bootWar任务。
依赖管理插件
需要明确地将负责处理依赖关系管理的dependency-management-plugin添加到项目中。
apply plugin: 'io.spring.dependency-management'
Spring-Boot-2.0.0-M2-发布说明
- Spring Boot 2.0.0 M2 Configuration Changelog
添加spring-boot-starter-quartz
有一款名为Quartz Job Scheduler的作业调度器已作为spring-boot-starter得到支持。
春天的数据网络配置
在application.properties文件中,可以进行分页和排序的设置。
# SpringDataWebProperties
spring.data.web.pageable.default-page-size= 20
spring.data.web.pageable.max-page-size= 2000
# Whether to expose and assume 1-based page number indexes.
spring.data.web.pageable.one-indexed-parameters= false
spring.data.web.pageable.page-parameter= page
# General prefix to be prepended to the page number and page size parameters.
spring.data.web.pageable.prefix= ""
# Delimiter to be used between the qualifier and the actual page number and size properties.
spring.data.web.pageable.qualifier-delimiter= _
spring.data.web.pageable.size-parameter= size
spring.data.web.sort.sort-parameter= sort
-
- prefix
各パラメータのprefixを指定します。
例) prefix=p_ → パラメータ名はp_pageやp_sizeとなります。
one-indexed-parameters
false、ページ番号の始まりを0とします。
page=0は1ページ目、page=1は2ページ目を指します。
true、ページ番号の始まりを1とします。
page=0とpage=1は同じ1ページ目、page=2は2ページ目を指します。
qualifier-delimiter
qualifierとパラメータの区切り文字を指定します。
1つのURLに2つ(以上)のページ情報を含めたい場合に利用します。
这个属性将会映射到SpringDataWebProperties类中。
示例代码
import org.springframework.data.domain.Pageable
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping(path = ["index"])
class IndexController {
// 例1
@GetMapping
fun index(pageable: Pageable): String {
return pageable.toString()
}
// 例2
@GetMapping(path = ["2"])
fun index2(@Qualifier("foo") foo: Pageable
, @Qualifier("bar") bar: Pageable): String {
println("foo: ${foo}")
println("bar: ${bar}")
return "OK"
}
}
例1:我昨天去了一个新的咖啡馆,里面的咖啡非常好喝。
http://localhost:9000/app/index
↓
Page request [number: 0, size 20, sort: UNSORTED]
http://localhost:9000/app/index?page=1&size=30&sort=id,desc&sort=name,asc
↓
Page request [number: 1, size 30, sort: id: DESC,name: ASC]
以下是英文句子「例2」的中文释义:
http://localhost:9000/app/index/2?foo_page=1&foo_size=10&bar_page=3&bar_size=10
↓
foo: Page request [number: 1, size 10, sort: UNSORTED]
bar: Page request [number: 3, size 10, sort: UNSORTED]
请注意。
需要注意的是,有类似于Spring Data Rest的参数。
# DATA REST (RepositoryRestProperties)
spring.data.rest.default-page-size= # Default size of pages.
spring.data.rest.limit-param-name= # Name of the URL query string parameter that indicates how many results to return at once.
spring.data.rest.max-page-size= # Maximum size of pages.
spring.data.rest.page-param-name= # Name of the URL query string parameter that indicates what page to return.
spring.data.rest.sort-param-name= # Name of the URL query string parameter that indicates what direction to sort results.
JDBCTemplate 配置
JDBCTemplate的设置现在可以在application.properties中完成。
spring.jdbc.template.fetch-size= -1
spring.jdbc.template.max-rows= -1
spring.jdbc.template.query-timeout=
这个属性将会反映在 JdbcProperties 类中。
Cassandra的连接池选项设置。
在application.properties文件中,可以进行池化选项的设置。
spring.data.cassandra.pool.heartbeat-interval= 30s
spring.data.cassandra.pool.idle-timeout= 120s
spring.data.cassandra.pool.max-queue-size= 256
spring.data.cassandra.pool.pool-timeout= 5000ms
这个属性将映射到CassandraProperties类中。
添加spring-boot-starter-json
有了替代Jackson-databind的spring-boot-starter-json的新增功能。
Maven (一种软件管理工具)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
Gradle:格雷德
compile("org.springframework.boot:spring-boot-starter-json")
而且,不再需要另外添加以下的依赖关系。
-
- jackson-datatype-jdk8
-
- jackson-datatype-jsr310
- jackson-module-parameter-names
更改spring-boot-starter-thymeleaf的内容。
由于spring-boot-starter-thymeleaf现在包含了对thymeleaf-extras-java8time的传递依赖关系,因此不需要再单独添加依赖关系了。
Mongo客户端的配置
可以使用MongoClientSettingsBuilderCustomizer来对Mongo客户端进行配置。
测试
已添加了用于单元测试的注解。
-
- JooqTest
- DataRedisTest
Spring-Boot-2.0.0-M3发布说明
- Spring Boot 2.0.0 M3 Configuration Changelog
★Maven插件的更改
如果要在目标中指定参数,通常会在参数名称的前缀加上”spring-boot”。
以下是一个例子。
Please provide the sentence that needs to be paraphrased.
直到1.5版本,用于指定配置文件的参数是run.profiles。
mvn spring-boot:run -Drun.profiles=foo
2.0版本及以后会将其更改为spring-boot.run.profiles。
mvn spring-boot:run -Dspring-boot.run.profiles=foo
开发工具的更改
不再支持通过HTTP进行远程调试。
Spring-Boot-2.0.0-M4版本发布说明
- Spring Boot 2.0.0 M4 Configuration Changelog
更改application.properties的命名空间
Liquibase和Flyway
数据库初始化程序
Spring Batch使用的数据库初始化控制属性已经发生了变化。此外,Spring Integration、Spring Session和QUARTZ SCHEDULER也可以通过类似的机制进行初始化。
可以指定的值是根据DataSourceInitializationMode定义的三种类型。
-
- always
Always initialize the datasource.
embedded
Only initialize an embedded datasource.
never
Do not initialize the datasource.
春季批处理
spring.batch.initializer.enabled= true
spring.batch.initialize-schema= embedded
这个属性会反映在BatchProperties类中。
春天融合
spring.integration.jdbc.initialize-schema= embedded
这个属性将反映在Class IntegrationProperties中。
春季会议
spring.session.jdbc.initialize-schema=embedded
这个属性将会在Class JdbcSessionProperties中体现。
石英调度器
spring.quartz.jdbc.initialize-schema= embedded
这个属性会被反映在类QuartzProperties中。
编译标志
在使用Spring Boot的Maven项目中,-parameters编译标志默认是启用的。
为了能够获取Reflection API的方法java.lang.reflect.Executable.getParameters的参数,将构造函数和方法的虚拟参数名称存储在生成的类文件中。
★支持
- Java9
Spring Boot 2.0.0 M5 发布说明
- Spring Boot 2.0.0 M5 Configuration Changelog
Maven Surefire插件的升级版本。
Maven Surefire插件的include/exclude设置已被更改。
下面是默认设置,适用于1.5版本。在2.0版本中,使用的Surefire插件版本已经升级,并且默认设置也发生了改变。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Tests.java</include>
<include>**/*Test.java</include>
</includes>
<excludes>
<exclude>**/Abstract*.java</exclude>
</excludes>
</configuration>
</plugin>
另外,如果要使用JUnit5,则需要将使用的Maven Surefire插件版本降低至2.19.1。
- Inclusions and Exclusions of Tests
插件版本的当前状态
我整理了默认使用的插件版本。







Gradle插件的修改
在bootRun任务中,可以指定应用程序参数(args)和JVM参数(jvmArgs)。
例子:请你帮忙把这本书拿给我。
bootRun {
args += ['-X', '-F']
jvmArgs += ['-Dspring.profiles.active=dev']
}
Redis驱动程序的更改
在spring-boot-starter-redis中,默认的Redis驱动程序由Jedis更改为Lettuce。
Mockito 1.x:
Mockito 1.x:检验框架
在 Mockito 1.x 版本中,无法使用 @MockBean 和 @SpyBean 来进行对象注入。
如果不使用 spring-boot-starter-test 库,就需要手动升级到 Mockito 2.x 版本。
支持
-
- OAuth 2.0
-
- Java9
-
- Micrometer 1.0.0-rc.2
- JSON-B
★ Spring Framework 5.0 GA
★ 春季框架5.0 GA
Spring Framework 5.0进入正式发布阶段。
从这个里程碑开始,Spring Framework 5.0 GA版已经开始使用。
Spring-Boot-2.0.0-M6发布说明
- Spring Boot 2.0.0 M6 Configuration Changelog
Gradle插件的更改
在BootRun、BootJar和BootWar任务中,现在可以使用mainClassName属性进行配置。在此之前,需要通过各个任务的属性进行设置。
JPA的open-in-view属性的警告
默认值为true,但如果不明确将该属性的值设置为true,则会在启动时显示警告消息。
spring.jpa.open-in-view= true
警告信息
spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
配置位置
在2.0版本中,设置application.properties的搜索路径的方法已经改变。
1.5之前,将路径设置为”spring.config.location”的路径会被添加到默认的搜索路径中。
从2.0开始,将路径设置为”spring.config.location”会替换掉默认的搜索路径。如果想要添加搜索路径,可以使用新的属性”additional-location”。
spring.config.additional-location= # Config file locations used in addition to the defaults.
ConfigurationProperties的验证
要对使用了ConfigurationProperties注解的对象进行验证,需要添加Validated注解。
可以只提供一种中文翻译的改写如下:
例子
如果要将以下属性绑定到FooConfig类中,可以这样做:
my-app.my-module.foo.first-name= ruby
#my-app.my-module.foo.last-name= tomato
#my-app.my-module.foo.age= 77
my-app.my-module.foo.bar-settings.max-height= 999
my-app.my-module.foo.bar-settings.min-height= 100
@Component
@ConfigurationProperties(prefix = "my-app.my-module.foo")
@Validated
class FooConfig {
lateinit var firstName: String
lateinit var lastName: String
var age: Int? = null
var barSettings: BarConfig = BarConfig()
class BarConfig {
lateinit var maxHeight: Integer
lateinit var minHeight: Integer
override fun toString(): String {
return "BarConfig(maxHeight=$maxHeight, minHeight=$minHeight)"
}
}
override fun toString(): String {
return "FooConfig(firstName='$firstName', lastName='$lastName', age=$age, barSettings=$barSettings)"
}
}
只要有验证过的注释,应用程序在启动时就会进行验证,如果NotNull属性无法初始化,则会输出错误并终止。
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to bind properties under 'my-app.my-module.foo.last-name' to java.lang.String:
Reason: Unable to get value for property last-name
Action:
Update your application's configuration
如果没有添加Validated注释,则应用程序会启动,但在首次访问FooConfig的属性时会发生错误。
kotlin.UninitializedPropertyAccessException: lateinit property lastName has not been initialized
产权的起源
如果无法将属性绑定(例如抛出BindException等原因),则会显示该属性的属性源。
当指定的属性“-Dmy-app.my-module.foo.color=white”无法与my-app.my-module.foo.color绑定时,将显示以下信息。原因是指定的“white”值无法绑定到枚举类型的Color字段。从消息中的“Origin”行可以确认该值是由“SystemProperties”指定的。
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to bind properties under 'my-app.my-module.foo.color' to com.example.demomavenspring2.type.Color:
Property: my-app.my-module.foo.color
Value: white
Origin: "my-app.my-module.foo.color" from property source "systemProperties"
Reason: Failed to convert from type [java.lang.String] to type [@javax.validation.constraints.NotNull com.example.demomavenspring2.type.Color] for value 'white'; nested exception is java.lang.IllegalArgumentException: No en
um constant com.example.demomavenspring2.type.Color.white
Action:
Update your application's configuration. The following values are valid:
BLUE
CYAN
GREEN
MAGENTA
RED
YELLOW
★数据源初始化
数据库的初始化控制属性已被修改。
spring.datasource.initialize= true
只有内置数据库(H2、HSQL、Derby)才能使用新属性,默认情况下。
spring.datasource.initialization-mode= embedded
在DataSourceInitializationMode中,可以指定的值有以下3种。当指定always时,需要注意即使不使用内嵌数据库也会启用该功能。
-
- embedded
Only initialize an embedded datasource.
always
always initialize the datasource.
never
Do not initialize the datasource.
JPA映射资源
现在可以指定映射资源文件。
spring.jpa.mapping-resources= # Mapping resources (equivalent to "mapping-file" entries in persistence.xml).
HTTP/2的中文释义
在这个里程碑中,Tomcat和Undertow已经对HTTP/2的启用/禁用进行了属性设置。 (Jetty在RC1中提供支持)
server.http2.enabled= true
要确认HTTP/2是否已启用,请启用SSL并通过HTTPS进行访问。
从自动配置和依赖关系管理中排除
如果在项目中使用,必须明确版本。
- Spring Mobile
Kotlin – Kotlin
已经准备了一个名为runApplication的内联函数。
1.5之前 (yī dì 5 zhī
fun main(args: Array<String>) {
SpringApplication.run(Application::class.java, *args)
}
在2.0版本及以后,也可以用以下方式进行描述。
fun main(args: Array<String>) {
runApplication<Application>(*args)
}
或者
fun main(args: Array<String>) {
runApplication<Application>(*args) {
// initialize code
}
}
Spring Boot 2.0.0的M7版本发布说明
- Spring Boot 2.0.0 M7 Configuration Changelog
更改Jackson序列化的默认值。
serialization.write-dates-as-timestamps属性的默认值已更改为false。
示例代码 ( )
我确认了下列数据类的实例将如何进行序列化。
data class DateTimeDemo(
var lt: LocalTime = LocalTime.now(),
var ld: LocalDate = LocalDate.now(),
var dt: LocalDateTime = LocalDateTime.now(),
var ym: YearMonth = YearMonth.now(),
var md: MonthDay = MonthDay.now(),
var dd: Duration = Duration.of(1, ChronoUnit.HOURS),
var pp: Period = Period.ofDays(1),
var ii: Instant = Instant.now()
) : Serializable
默认情况下是2.0版本。
spring.jackson.serialization.write-dates-as-timestamps= false
spring.jackson.serialization.write-durations-as-timestamps= true
请用中文进行本地化重述,只需提供一种选项:
↓
请将以下内容用中文重新表达,只需提供一种选项:
{
lt: "14:06:20.9023938",
ld: "2018-02-16",
dt: "2018-02-16T14:06:20.9023938",
ym: "2018-02",
md: "--02-16",
dd: "PT1H",
pp: "P1D",
ii: "2018-02-16T05:06:20.904893500Z"
}
当1.5被设置为默认值时(也适用于Jackson的默认值)
spring.jackson.serialization.write-dates-as-timestamps= true
spring.jackson.serialization.write-durations-as-timestamps= true
请用中文翻译以下内容(只需提供一种选择):
↓
{
lt: [
14,
7,
43,
61545000
],
ld: [
2018,
2,
16
],
dt: [
2018,
2,
16,
14,
7,
43,
61545000
],
ym: [
2018,
2
],
md: "--02-16",
dd: 3600,
pp: "P1D",
ii: 1518757663.0645459
}
Kotlin – Kotlin is a programming language that can be used natively in Chinese.
删除了spring-boot-starter-json对jackson-module-kotlin的传递性依赖关系。
如果在Kotlin中使用jackson,则需要手动添加依赖关系。
魔镜
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>
Gradle
进阶
compile("com.fasterxml.jackson.module:jackson-module-kotlin")
Spring Data仓库的启用功能
通过添加一个反应性的数据存储库,已改变存储库启用/禁用属性。
在以往的属性中,我们使用true/false来进行设置。
spring.data.cassandra.repositories.enabled=
spring.data.mongodb.repositories.enabled=
spring.data.redis.repositories.enabled=
spring.data.couchbase.repositories.enabled=
在Redis以外的部分,可以选择新的属性,包括auto(默认)、imperative、reactive和none。
Redis似乎没有任何变化,仍然保持以前的样子。
spring.data.cassandra.repositories.type= auto
spring.data.mongodb.repositories.type= auto
spring.data.redis.repositories.enabled= true
spring.data.couchbase.repositories.type= auto
-
- auto
enables all repository types automatically based on their availability
imperative
enables imperative repisitories
reactive
enables reactive repositories
none
enables no repositories
只有Redis没有type属性。
当检查每个starter的pom.xml文件时(spring-boot-starter-data-redis、spring-boot-starter-data-redis-reactive),可以看出,reactive版本似乎只是传统版本的别名,没有任何区别。
排除自动配置和依赖关系管理
如果在项目中使用,就需要明确版本。
-
- Spring Social
- commons-digester
重启时的条件评估差异
启用了DevTools的应用程序在启动期间,当类路径更新时会自动重新启动。
更新类路径的方法因IDE而异。在Eclipse中,当保存更改的文件时,在IntelliJ IDEA中,项目构建(Ctrol + F9)或文件重新编译(Ctrl + Shift + F9)也会产生相同的效果。
要控制重新启动,请设置以下属性。
spring.devtools.restart.enabled= false
当检测到在重新启动时应用程序的自动配置发生更改,更改内容将被输出到名为”CONDITION EVALUATION DELTA”的报告中。(需要注意的是,在停止和启动时不会输出报告,仅在自动重启时才会输出。)若要控制报告的输出,请设置以下属性。
spring.devtools.restart.log-condition-evaluation-delta= false
application.properties文件中的Duration类型
如果属性是Java Duration类型,现在可以在后缀中添加单位来指定,例如”1h”。
server.session.cookie.max-age= 1h
如果不添加后缀,则将保持传统的单位。
# Maximum age of the session cookie. If a duration suffix is not specified, seconds will be used.
server.session.cookie.max-age= 3600
然而,由于还存在一些不接受Duration类型参数的属性需要指定时间的长度,所以需要注意。
举个例子,下面的max-age是Long类型,如果添加后缀会导致错误。
spring.datasource.tomcat.max-age= 30s
当使用Redis作为缓存时的默认设置。
现在可以在application.properties中设置使用Redis作为缓存的默认值。
选择Redis作为缓存。
spring.cache.type= redis
您可以在以下属性中设置默认值。
spring.cache.redis.time-to-live= 120s
spring.cache.redis.cache-null-values= true
spring.cache.redis.use-key-prefix= true
spring.cache.redis.key-prefix= myCache_
此属性将反映到Class CacheProperties中。
当将cache-null-values属性设置为false时,试图缓存null值会抛出IllegalArgumentException异常。
在这种情况下,可以设置如下来排除null值。
@Cacheable(cacheNames = ["myCache"], unless="#result == null")
添加spring-boot-starter-data-couchbase-reactive
Couchbase已经被添加到支持Reactive应用的数据仓库中了。(MongoDB、Redis、Cassandra在M1中已经支持)
-
- spring-boot-starter-data-couchbase
- spring-boot-starter-data-couchbase-reactive
Spring Boot 2.0.0 RC1 发布说明
-
- Spring Boot 2.0.0 RC1 Configuration Changelog
- asciidoc
删除对spring-boot-starter-web的依赖
spring-boot-starter-freemarker的依赖已被移除并转为依赖于spring-boot-starter-web。(spring-boot-starter-mustache和spring-boot-starter-thymeleaf在M1版本中已做相应更新)
Spring MVC路径匹配的更改 (Simplified Chinese)
后缀路径匹配的默认行为已经改变。
因此,新增了一个新参数。
spring.mvc.content-negotiation.favor-parameter= false
spring.mvc.content-negotiation.favor-path-extension= false
spring.mvc.content-negotiation.parameter-name=
1.5以内,例如这些请求全部可以。
localhost://app/product
localhost://app/product.json
localhost://app/product.xml
尽管下述处理程序方法曾映射过,但从2.0版本开始,默认情况下不再进行映射 (返回404 Not Found)。
@GetMapping(path = ["/app/product"])
fun product(): String {
//... 省略
}
更改 application.properties 的命名空间
★遗产属性迁移
由于属性文件的结构发生了重大变化,因此提供了一个名为spring-boot-properties-migrator的属性文件迁移模块。
当集成这个模块时,它会在应用程序启动时显示警告,如果存在旧属性,并且将临时将其转换为新结构后启动应用程序。
需要提醒的是,它不会自动转换application.properties文件,所以修正工作需要手动进行。
专家
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
</dependency>
Gradle (natively in Chinese: 构建工具).
runtime("org.springframework.boot:spring-boot-properties-migrator")
例如
如果存在以下类似的旧格式描述
banner.charset: UTF-8 # Banner file encoding.
应用程序启动时会显示警告信息。
WARN 7460 --- [ restartedMain] o.s.b.c.p.m.PropertiesMigrationListener :
The use of configuration keys that have been renamed was found in the environment:
Property source 'applicationConfig: [classpath:/application.properties]':
Key: banner.charset
Line: 2
Replacement: spring.banner.charset
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.
Hibernate属性的配置
您可以自定义Hibernate的属性。
程式範例
@Bean
fun customizer() = HibernatePropertiesCustomizer { props ->
props["hibernate.show_sql"] = true
props["hibernate.format_sql"] = true
props["hibernate.use_sql_comments"] = true
props["hibernate.generate_statistics"] = true
}
在application.properties文件中,您可以使用以下属性进行自定义配置。
spring.jpa.properties.hibernate.*
- User Guild / configurations
Redis的配置
可以通过RedisCacheConfiguration来配置RedisCacheManager。
@Bean
fun redisCacheConfig() = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(2))
.disableCachingNullValues()
在application.properties文件中,您可以通过以下属性进行定制。
spring.cache.redis.*
支持
-
- GSon
- HTTP/2 (Jetty)
Spring Boot 2.0.0 RC2 发行说明
- Spring Boot 2.0.0 RC2 Configuration Changelog
更改application.properties
以下的属性已经重新配置。(似乎在RC2中进行了修订)
端点网络配置
management.endpoints.web.expose
请将以下内容用中文进行重述,仅提供一种选择:
↓
请用中文进行重新表达,只需要一种选项:
management.endpoints.web.exposure.include
management.endpoints.web.exposure.exclude
JMX 配置的端点
management.endpoints.jmx.expose
请用汉语将以下内容进行释义,只需要提供一种版本:
↓
management.endpoints.jmx.exposure.include
management.endpoints.jmx.exposure.exclude
Webjars Locator的依赖管理变更
webjars-locator的依赖管理已被更改为webjars-locator-core。
从2.0开始
Maven 马文
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator-core</artifactId>
<version>0.35</version>
</dependency>
Gradle – 灵活强大的构建工具
compile("org.webjars:webjars-locator-core:0.35")
Kotlin – Kotlin语言
在Spring Boot参考文档的第47节中,添加了对Kotlin的支持。
- Part IV. Spring Boot features | 47. Kotlin support
另外,在Spring Framework的参考资料中也有关于Kotlin的部分。
- Spring Framework | Language Support
自定义绑定分隔符
过去,如果属性的类型是集合,并且绑定的值(例如在application.properties中定义)是用逗号分隔的,则会自动将其绑定到集合中。
my-app.my-module.foo.hobbies= shopping,trekking,movies
@Component
@ConfigurationProperties(prefix = "my-app.my-module.foo")
data class FooConfig(
var hobbies: List<String> = mutableListOf()
)
从2.0版本开始,你可以使用分隔符注释来指定分隔符。
my-app.my-module.foo.hobbies= shopping; trekking; movies
@field:Delimiter(value = ";")
var hobbies: List<String> = mutableListOf()
如果不想使用逗号分隔划分,可以按照以下方式指定。
@field:Delimiter(value = Delimiter.NONE)
支持
Micrometer 1.0-GA
M5では1.0.0-RC2でしたが、GAをサポートします。
检测JOOQ的SQLDialect。
默认情况下自动检测是启用的,通常无需在application.properties中明确说明。
spring.jooq.sql-dialect= # SQL dialect to use. Auto-detected by default.
- org.jooq.SQLDialect
附加说明的发布说明。
Spring Boot 2.0迁移指南基本上总结了从M1到RC2的内容,但由于迁移指南中只记录了一些事项,因此我将补充说明。
更改spring.jpa.hibernate.ddl-auto的默认行为。
在使用内置数据库时,默认值为create-drop,其他情况下为none,直到1.5版本。
2.0版本及以后的默认设置是,在使用内嵌数据库且未使用flyway/Liquibase时,采用create-drop策略;否则使用none策略。
这个属性似乎不能更改其可设置的值的内容。
-
- create-drop
Create and then destroy the schema at the end of session
create
Create the schema and destroy previous data
none
Disable DDL handling
update
Update the schema if necessary
validate
Validate the schema, make no changes to the database
Spring Data版本升级的影响
-
- Spring Data JPA – Reference Documentation – Version 1.11.10.RELEASE
- Spring Data JPA – Reference Documentation – Version 2.0.4.RELEASE
Spring Data Commons和Jpa也进行了版本升级。
由于这个版本升级,可能需要修改实现代码,因为接口发生了改变。
关于CrudRepository接口,有以下的区别。
@NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID>
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID>