Spring Boot儼然已經成為Java Web的開發標準,但是使用上發現千人千面,這裡整理了一些在使用Spring Boot使用中常見的情況,希望作為一個小小的Guideline來幫助專案中同事統一用法,也包含了一些小小的Best Practices。
可能內容並不太適合Spring Boot的初學者或者對Spring還很陌生的讀者。
I. Prerequisites
我們專案中使用Spring Boot的基本準則是:
- 配置最小化,通用配置儘量採用Spring Boot的自動配置(auto configuration),通過Spring Boot推薦的方式來完成配置的自定義。
- 儘量採用Java-based配置的方式(這一點只是個人偏好而已)。
- 儘量採用Spring Boot推薦的包結構。
- 本系列採用的Spring Boot版本為:1.5.3.RELEASE;
- JDK 版本 1.8 or later;
- Maven 3.0+;
- 開發工具推薦 IntelliJ IDEA(Community版即可);
II. 依賴管理
Spring Boot推薦使用spring-boot-starter-parent
作為專案的POM的Parent,不過我們的專案推薦使用的是Spring IO Platform:
<parent>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>Brussels-SR2</version>
</parent>複製程式碼
Spring IO Platform包含了Spring模組和大量的第三庫版本(可以檢視這些庫的版本),都是經過測試可以完美工作的。
事實上,如果是檢視一下Spring IO Platform POM檔案,會發現他繼承了spring-boot-starter-parent
,所以說一般情況下你基於Spring Boot的專案可以直接用Spring IO Platform作為parent。因為Spring IO Platform提供了spring-boot-starter-parent
的超集,包含了許多spring-boot-starter-parent
中沒有提供的依賴,比如com.google.protobuf
等。
III. 選擇合適的starter
Starter應該是Spring Boot提供的最大便利了,其提供了某個feature所需依賴的配置和自動配置相關Bean的服務。例如spring-boot-starter-data-redis
,會幫我們自動引入jedis等依賴,並且提供開箱即用的RedisConnectionFactory
, StringRedisTemplate
, RedisTemplate
例項。
除了官方提供的starter,還有許多第三方starter能幫我們節省很大的精力,比如mybatis-spring-boot-starter
讓我們不用再關心mybatis的依賴引入和配置,pagehelper-spring-boot-starter
讓我們一行程式碼搞定翻頁。
IV. 合理的Package Structure
假設我們的專案是一箇中等專案,並沒有採用流行的微服務架構,而是包含多個modules,例如:
└── service-lib //包含entity、dao、service等基礎業務程式碼
└── api //依賴於service-lib,提供REST API
└── tasks //依賴於service-lib,執行一些Scheduled tasks複製程式碼
其中service-lib的包結構大致如下:
src/main/java/
└── com
└── bytecho
└── sample
└── lib
├── ServiceLibraryConfig.java ❶
├── mappers
├── models
├── services
└── utils複製程式碼
❶ ServiceLibraryConfig
內容:
@Configuration
@EnableAsync
@EnableCaching(proxyTargetClass = true)
public class ServiceLibraryConfig {
@Bean
public RedisTemplate<Object, Object> redisTemplate(JedisConnectionFactory jedisConnectionFactory) {
//省略
return template;
}
//...各種配置
}複製程式碼
api module包結構如下:
src/main/java/
└── com
└── bytecho
└── sample
├── APIWebServer.java
└── web
├── advices
├── controllers
├── ...複製程式碼
APIWebServer
的內容:
@SpringBootApplication
public class APIWebServer {
public static void main( String[] args ) {
SpringApplication.run(APIWebServer.class, args);
}
}複製程式碼
@SpringBootApplication
這個註解,我們都知道其等價於三個註解@Configuration
、@EnableAutoConfiguration
、@ComponentScan
,
由於註解標註的類APIWebServer
位於package:com.bytecho.sample
下,@ComponentScan
會幫助我們自動掃描這個包下所有的Component、Services以及Configuration,所以service-lib這個專案下所有的元件都會放到相應context裡,不用我們再顯式的去@Import(ServiceLibraryConfig.class)
,也不用再去宣告component scan需要掃描的package路徑。
V. 配置檔案及Profiles
推薦使用Multi-profile YAML documents,即各環境配置放在同一配置檔案application.yml
中。
spring:
profiles:
active: dev
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
hikari:
connection-timeout: 10000 #10 sec
maximum-pool-size: 15
---
spring:
profiles: dev
datasource:
url: jdbc:mysql://127.0.0.1:3306/bytecho?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
username: bytecho
password: bytecho111
redis:
host: 127.0.0.1
port: 17500
password: bytecho111
---
spring:
profiles: staging
datasource:
url: jdbc:mysql://10.10.11.11:3306/bytecho?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
username: bytecho_test
password: bytecho_test
redis:
host: 10.10.11.11
port: 17500
password: bytecho_test
---
spring:
profiles: production
#省略複製程式碼
簡單的專案這樣做比較一目瞭然,啟動的時候通過命令列引數指定當前profile:--spring.profiles.active=prod
VI. 日誌處理
浩瀚的Java世界裡有為數眾多的Logging框架,於是勤勞的Java程式設計師們又發明了不同的Logging Facade代理底層的Logging框架來解耦(設計模式的使用真是爐火純青)。
- Logging Facade: Commons Logging, SLF4J
- Logging Infrastructure: java.util.logging, Log4J, Logback
Spring Boot底層使用Commons Logging作為Facade。如果引入了starter(所有starter依賴於spring-boot-starter-logging),Spring Boot預設會使用底層日誌框架為Logback。
簡單的配置可以直接在application.properties
(application.yml
)中完成:
logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.com.bytecho.sample=DEBUG
logging.file=/opt/logs/api.log複製程式碼
當然為了減小application.properties
的體積和更大的定製性,我們使用推薦的logback-spring.xml
來完成對Logback的配置,程式碼中使用SLF4J作為facade。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" /> ❶
<property name="LOG_FILE" value="${LOG_FILE:-/opt/logs/sample.log}"/> ❷
<include resource="org/springframework/boot/logging/logback/console-appender.xml" /> ❸
<springProfile name="dev"> ❹
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
<logger name="com.bytecho.sample" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
</springProfile>
<springProfile name="staging,production"> ❺
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_FILE}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE}.%d{yyyyMMdd}</fileNamePattern>
</rollingPolicy>
<encoder>
<charset>UTF-8</charset>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<root level="WARN">
<appender-ref ref="FILE" />
</root>
<logger name="com.bytecho.sample" level="INFO" additivity="false">
<appender-ref ref="FILE" />
</logger>
</springProfile>
</configuration>複製程式碼
❶ 這裡引入Spring Boot自帶的一些配置:預設的Log Pattern,一些第三方庫預設的日誌級別等;
❷ 注意這裡${variable:-defaultValue}
的形式是Logback自己的Variable Substitution,LOG_FILE來自於Spring Environment中的logging.file,你可以在application.properties中配置,Spring Boot幫你把該值放入了System properties,如果沒有,取預設值/opt/logs/sample.log
;
❸ 預設的console-appender,也可以參考這個檔案內容自己來配置;
❹和❺為Spring Boot對Logback的擴充套件,支援對不同profile採用不同的日誌配置。