Spring Boot In Practice (0):基礎

我真的是故意的發表於2017-06-08

Spring Boot儼然已經成為Java Web的開發標準,但是使用上發現千人千面,這裡整理了一些在使用Spring Boot使用中常見的情況,希望作為一個小小的Guideline來幫助專案中同事統一用法,也包含了一些小小的Best Practices。

可能內容並不太適合Spring Boot的初學者或者對Spring還很陌生的讀者。

I. Prerequisites

我們專案中使用Spring Boot的基本準則是:

  1. 配置最小化,通用配置儘量採用Spring Boot的自動配置(auto configuration),通過Spring Boot推薦的方式來完成配置的自定義。
  2. 儘量採用Java-based配置的方式(這一點只是個人偏好而已)。
  3. 儘量採用Spring Boot推薦的包結構。
  1. 本系列採用的Spring Boot版本為:1.5.3.RELEASE
  2. JDK 版本 1.8 or later;
  3. Maven 3.0+;
  4. 開發工具推薦 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框架來解耦(設計模式的使用真是爐火純青)。

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採用不同的日誌配置。

VII. 參考

Using Logback with Spring Boot - Spring Framework Guru

相關文章