1. 程式人生 > >Spring Boot技術指南--第四部分 Spring Boot特性

Spring Boot技術指南--第四部分 Spring Boot特性

這一章我們將更深入的學習Spring Boot,學習如何使用和定製它的特性。

23 SpringApplication

SpringApplicationmain啟動來引導Spring Boot。

public static void main(String[] args){
	SpringApplication.run(MySpringConfiguration.class,args);
}

應用啟動:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::   v1.5.16.RELEASE

2013-07-31 00:08:16.117  INFO 56603 --- [           main] o.s.b.s.app.SampleApplication            : Starting SampleApplication v0.1.0 on mycomputer with PID 56603 (/apps/myapp.jar started by pwebb)
2013-07-31 00:08:16.166  INFO 56603 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot
[email protected]
6e5a8246: startup date [Wed Jul 31 00:08:16 PDT 2013]; root of context hierarchy 2014-03-04 13:09:54.912 INFO 41370 --- [ main] .t.TomcatEmbeddedServletContainerFactory : Server initialized with port: 8080 2014-03-04 13:09:56.501 INFO 41370 --- [ main] o.s.b.s.app.SampleApplication : Started SampleApplication in 2.992 seconds (JVM running for 3.658)

23.1 啟動失敗

如果應用啟動失敗,FailureAnalyzers會提供錯誤資訊和修復建議,例子:

***************************
APPLICATION FAILED TO START
***************************

Description:

Embedded servlet container failed to start. Port 8080 was already in use.

Action:

Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.

如果沒有能處理異常的分析器,你可以通過設定debug屬性或者允許DEBUG日誌org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer)來顯示完整的錯誤日誌 使用debug模式啟動: $ java -jar myproject-0.0.1-SNAPSHOT.jar --debug

23.2 定製Banner

在classpath中banner.txt檔案,或者使用banner.location來自定義banner檔案的地址,也可以使用classpath中的banner.gifbanner.jpg或者banner.png檔案,或者設定banner.image.location屬性來設定它,圖片會轉換為ASCII顯示出來 在banner.txt中可以使用的預製值:

變數 描述
${application.version} MANIFEST.MF的版本號,例如:Implementation-Version:1.0中的1.0
${application.formatted-version} MANIFEST.MF中版本號的顯示格式,例如v1.0
${spring-boot.version} 使用的Spring Boot版本,例如:1.5.16.RELEASE
${spring-boot-formatted-version} Spring Boot版本格式,例如:v1.5.16.RELEASE
${Ansi.Name}或者${AnsiColor.NAME}或者${AnsiBackground.NAME}或者${AnsiStyle.NAME} NAME的ANSI轉義碼位置
${application.title} 宣告在MANIFEST.MF中的應用頭,例如Implementation-Title:MyApp,會顯示MyApp

注意:SpringApplication.setBanner(...)也可以用來硬編碼的方式設定banner,使用org.springframework.boot.Banner介面和實現自己的printBanner() 你也可以使用spring.main.banner-mode屬性來設定是否顯示banner,或者顯示在哪裡(System.out或者Console),設定的值是:logoff springBootBanner是一個單例項的類,用來列印banner YAML設定off

spring:
	main:
		banner-mode:"off"

23.3 定製SpringApplication

例如:

public static void main(String[] args){
	SpringApplication app = new SpringApplication(MySpringConfiguration.class);
	app.setBannerMode(Banner.Mode.OFF);
	app.run(args);
}

SpringApplication構造器的引數是配置類,一般是@Configuration註解的類 Spring Boot也提供了使用application.properties來配置SpringApplication,完整的配置選項,參考SpringApplicatoin Javadoc

23.4 流式API風格

如果你想構建多層ApplicationContext,或者使用“fluent”API風格,那你就可以使用SpringApplicationBuilder 例如:

new SpringApplicationBuilder()
				.sources(Parent.class)
				.child(Application.class)
				.bannerMode(Banner.Mode.OFF)
				.run(args);

ApplicationContext的限制條件:Web元件必須使一個子上下文,而且相同的Environment使用相同的父和子上下文,參考SpringApplicationBuilderJavadoc

23.5 應用事件和監聽

除了常見的Spring框架的事件外,比如:ContextRefreshedEventSpringApplication會觸發一些額外的應用事件。

有一些事件是在ApplicationContext建立前就被觸發了,因此你不能在宣告的@Bean上給它們註冊監聽,你可以使用SpringApplication.addListeners(...)或者SpringApplicationBuilder.listeners(...)方法給它們註冊監聽 如果你想要自動的方式註冊監聽,你可以在專案中建立META-INF/spring.factories檔案,然後使用org.springframework.context.ApplicationListener鍵引用你定義的監聽例如: org.springframework.context.ApplicationListener=com.example.project.MyListener

應用事件觸發順序:

  1. ApplicationStartingEvent在應用開始執行時,除了註冊和例項化監聽器之外的所有處理之前觸發
  2. ApplicationEnvironmentPreparedEvent在載入Environment時,建立上下文之前觸發
  3. ApplicationPreparedEvent在重新整理啟動,bean載入完成後觸發
  4. ApplicationReadyEvent在重新整理啟動後,所有的回撥都執行完畢,通知應用準備好接受請求的時候觸發
  5. ApplicationFailedEvent在啟動失敗有異常時觸發 一般不需要關注應用事件,但是需要知道它的存在,Spring Boot使用事件機制處理各種任務 應用事件使用的是Spring框架的釋出機制。它是確認機制的一部分,它監聽釋出到子上下文和父上下文之中的事件。這樣的結果就是,如果你的應用使用了SpringApplication的層級結構,你的監聽器可能會收到多重的事件訊息。 如果要區分事件是本身層級的還是子層級的,就應該要求事件標明它的層級。通過實現ApplicationContextAware或者使用@Autowired

23.6 Web環境

SpringApplication依賴你是否是web開發環境來建立ApplicationContextAnnotationConfigApplicationContext是非web環境的,AnnotationConfigEmbeddedWebApplicationContext是web環境的。 你可以使用setWebEnvironment(boolean webEnvironment)來指定是否是web環境,從而來控制生成的ApplicationContext 也可以使用ApplicationContextsetApplicationContextClass(...)來控制 一般在單元測試時使用SpringApplicationsetWebEnvironment(false)來禁用web環境

23.7 訪問應用引數

可以使用SpringApplication.run(...)注入org.springframework.boot.ApplicationArguments來訪問應用的引數。ApplicationArguments這個介面提供了String[]有引數和無引數的解析方式訪問

import org.springframework.boot.*
import org.springframework.beans.factory.annotation.*
import org.springframework.stereotype.*

@Component
public class MyBean {

    @Autowired
    public MyBean(ApplicationArguments args) {
        boolean debug = args.containsOption("debug");
        List<String> files = args.getNonOptionArgs();
        // if run with "--debug logfile.txt" debug=true, files=["logfile.txt"]
    }

}

Spring Boot會給Environment註冊CommandLinePropertySource,也可以使用@Value註解來注入引數

23.8 使用ApplicationRunner或者CommandLineRunner

如果你需要在SpringApplication啟動時就執行一些指定的程式碼,你可以通過實現ApplicationRunner或者CommandLineRunner介面來實現,這兩個介面的工作方式一樣,都是提供一個run方法在SpringApplication.run(...)完成之前呼叫。 CommandLineRunner介面提供字串陣列的方式訪問應用引數的方法,而ApplicationRunner則是使用ApplicationArguments介面的方式訪問應用引數

import org.springframework.boot.*
import org.springframework.stereotype.*

@Component
public class MyBean implements CommandLineRunner {

    public void run(String... args) {
        // Do something...
    }

}

可以使用實現org.springframework.core.Ordered介面或者使用org.springframework.core.annotation.Order註解的方式來定義CommandLineRunnber或者ApplicationRunner的執行順序

23.9 應用退出

每一個SpringApplication都會基於JVM註冊一個應用關閉鉤子程式來保證ApplicationContext被完全關閉。所有的標準Spring 生命週期回撥,例如DisposableBean介面、@PreDestroy註解都可以用來實現這個目的。 另外,beans可以實現org.springframework.boot.ExitCodeGenerator介面定製在執行SpringApplication.exit()時執行特殊的動作,這些程式碼可以通過System.exit()返回它的執行狀態碼

@SpringBootApplication
public class ExitCodeApplication {

	@Bean
	public ExitCodeGenerator exitCodeGenerator() {
		return new ExitCodeGenerator() {
			@Override
			public int getExitCode() {
				return 42;
			}
		};
	}

	public static void main(String[] args) {
		System.exit(SpringApplication
				.exit(SpringApplication.run(ExitCodeApplication.class, args)));
	}

}

ExitCodeGenerator介面的實現可能會出現異常,當出現時,Spring Boot會通過getExitCode()方法返回它的狀態碼

23.10 管理特性

通過設定spring.application.admin.enabled屬性來開通應用的管理特性。這些暴露MBeanServer平臺下的[SpringApplicationAdminMXBean](https://github.com/spring-projects/spring-boot/tree/v1.5.16.RELEASE/spring-boot/src/main/java/org/springframework/boot/admin/SpringApplicationAdminMXBean.java),可以使用這個特性遠端管理Spring Boot應用。 使用local.server.port獲取應用的埠號 要小心使用MBean暴露的方法關閉應用

24 外部化配置

Spring Boot允許把配置外部化,這樣就可以實現同一套程式碼使用多套不同的環境配置了,你可以使用Properties檔案、YAML檔案、環境變數、命令列引數等外部化配置資訊,屬性值使用@Value註解注入到beans,也可以使用Environment抽象類或者使用@ConfigurationProperties註解將值繫結到物件上 Spring Boot使用獨有PropertySource順序的設計來繫結值,它的順序是:

  1. ~/.spring-boot-devtools.properties中的Devtools global settings properties,如果devtools被啟用時
  2. 在測試中的@[TestPropertySource](https://docs.spring.io/spring/docs/4.3.19.RELEASE/javadoc-api/org/springframework/test/context/TestPropertySource.html)註解
  3. 命令列引數
  4. SPRING_APPLICATION_JSON檔案中的屬性
  5. ServletConfig初始化引數
  6. ServletContext初始化引數
  7. java:comp/env中的JNDI屬性
  8. System.getProperties()獲取的Java系統引數
  9. 作業系統環境變數
  10. 僅包含random.*RandomValuePropertySource中的引數
  11. 包內部的引數
  12. jar包外部的 application.properties引數
  13. jar包內部的application.properties引數
  14. @Configuration註解的類中的@PropertySource
  15. 預設的配置屬性檔案(通過SpringApplication.setDefaultProperties指定預設配置)
import org.springframework.stereotype.*
import org.springframework.beans.factory.annotation.*

@Component
public class MyBean {

    @Value("${name}")
    private String name;

    // ...

}

在classpath下的application.properties提供預設的設定,當執行一個新環境時,提供一個外部的application.properties覆蓋預設的設定;可以使用java -jar app.jar --name="Spring"來指定引數 SPRING_APPLICATION_JSON可以提供命令列引數,例如: $ SPRING_APPLICATION_JSON='{"foo":{"bar":"spam"}}' java -jar myapp.jar 也可以使用spring.application.json來指定命令列引數: $ java -Dspring.application.json='{"foo":"bar"}' -jar myapp.jar 或者 $ java -jar myapp.jar --spring.application.json='{"foo":"bar"}' 或者使用JNDI變數 java:com/env/spring.application.json

24.1 配置隨機值

RandomValuePropertySource用來注入隨機值,可提供integers、longs、uuids、strings等等型別

my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}

random.*的語法:OPEN value (,max) CLOSEOPEN,CLOSE可以是任何的字元,value,max是integers

24.2 應用屬性檔案

SpringApplicationapplication.properties中載入配置資訊,把它們載入到Environment,載入路徑:

  1. /config目錄和子目錄
  2. 當前目錄
  3. classpath下的/config
  4. classpath根目錄

按照1,2,3,4的優先順序載入 可以使用YAML(.yml)檔案代替.properties檔案 如果不想使用application.properties作為配置檔案,可以使用spring.config.name指定配置檔案的名稱,也可以使用spring.config.location指定配置檔案的路徑 $ java -jar myproject.jar --spring.config.name=myproject 或者 $ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties 如果spring.config.location包含有目錄,應該使用/結束,而且是在spring.config.name之前載入 下面是配置檔案載入順序:

  1. file:./config/
  2. file:./
  3. classpath:/config/
  4. classpath:/

配置了配置檔案路徑,它會被自動新增到預設配置檔案路徑。自定義的路徑在預設路徑之前搜尋,例如: 如果你定義了路徑classpath:/custom-config/,file:./custom-config/,那麼搜尋順序就變成了:

  1. file:./custom-config/
  2. classpath:custom-config/
  3. file:./config/
  4. file:./
  5. classpath:/config/
  6. classpath:/

你可以通過在其中一個配置檔案中設定值來覆蓋載入順序。你可以在application.properties中指定或者使用spring.config.name指定,這些預設值可以在執行時被覆蓋

如果你使用的是環境變數,而不是系統變數,大部分的作業系統會禁止一些鍵名,但是你可以使用下劃線代替.,例如:使用SPRING_CONFIG_NAME代替spring.config.name

24.4 定製化配置檔案

除了application.properties之外,可以定製化配置檔案,例如application-{profile}.propertiesEnvironment有一個預設的環境(default),例如:application-default.properties 定製化配置檔案和標準配置檔案application.properties一樣被載入,定製化的配置檔案會覆蓋非定製化的值,不管它是在jar內部還是外部

24.5 佔位符

application.properties中可以使用佔位符,例如:

app.name=MyApp
app.description=${app.name} is a Spring Boot application

24.6使用YAML代替Properties

YAML是JSON的超集,而且有非常好的層級結構,SpringApplication支援使用YAML代替Properties,前提是要SnakeYAML包在classpath下

24.6.1 載入YAML

Spring框架提供兩個方便的類可以用來載入YAML文件,YamlPropertiesFactoryBean會把YAML載入為Properties,而YamlMapFactoryBean會把YAML載入為Map 例如:

environments:
		dev:
				url: http://dev.bar.com
				name: Devloper Setup
		prod:
				url: http://foo.bar.com
				name: My Cool App

被翻譯成Properties:

environments.dev.url=http://dev.bar.com
environments.dev.name=Developer Setup
environments.prod.url=http://foo.bar.com
environments.prod.name=My Cool App

YAML可以使用[index]格式:

my:
	servers:
			- dev.bar.com
			- foo.bar.com

被翻譯成Properties:

my.servers[0] = dev.bar.com
my.servers[1] = foo.bar.com

使用java.util.List或者Set來繫結資料,繫結到的bean需要提供setter方法:

@ConfigurationProperties(prefix="my")
public class Config {

    private List<String> servers = new ArrayList<String>();

    public List<String> getServers() {
        return this.servers;
    }
}
	需要注意下格式:
	my:
		servers: dev.bar.com,foo.bar.com
	是不能正常解析的

24.6.2 暴露YAML屬性

YamlPropertySourceLoader類暴露YAML屬性到PropertySource,可以使用@Value來訪問它的屬性的值

24.6.3 多賬號YAML文件

例:

server:
		address: 192.168.1.100
---
spring:
		profiles: development
server:
		address: 127.0.0.1
---
spring:
		profiles: production
servers:
		address: 192.168.1.120

上面的例子中,如果使用spring.profiles設定了development,則server.address的屬性為12.0.0.1,如果是production,則server.address的屬性為192.168.1.120 如果沒有明確指定定製環境,則預設的環境被啟用

server:
  port: 8000
---
spring:
  profiles: default
security:
  user:
    password: weak

24.6.4 YAML不足

YAML檔案不能通過@PropertySource註解載入

24.6.4 YAML檔案合併

YAML最終都會被翻譯成Properties,這個過程中可能會出現重寫list屬性出錯的問題 假設MyPojo有兩個屬性namedescription,預設值是null

@ConfigurationProperties("foo")
public class FooProperties {

    private final List<MyPojo> list = new ArrayList<>();

    public List<MyPojo> getList() {
        return this.list;
    }

}

下面是配置:

foo:
  list:
    - name: my name
      description: my description
---
spring:
  profiles: dev
foo:
  list:
    - name: my another name

假如dev未被啟用,則FooProperties.list中包含一個MyPojo實體,假如dev被啟用,則list中還是包含一個實體(nam=“my another name”,description=null)這個配置不會載入第二個MyPojo實體,而且不會修改它們 一個多配置的集合中,只有最高優先順序的一個被使用,而且是隻有這一個

foo:
  list:
    - name: my name
      description: my description
    - name: another name
      description: another description
---
spring:
  profiles: dev
foo:
  list:
     - name: my another name

上面的例子中,假設dev被啟用,FooProperties.list只包含一個MyPojo實體,name=my another name,description=null

24.7 型別安全配置屬性

使用@Value("${property}")註解來注入配置的值有時候難於處理,尤其是有多個配置檔案或者資料有多層級的時候,Spring Boot提供強型別beans的方法來獲取和校驗配置資訊

package com.example;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("foo")
public class FooProperties {

    private boolean enabled;

    private InetAddress remoteAddress;

    private final Security security = new Security();

    public boolean isEnabled() { ... }

    public void setEnabled(boolean enabled) { ... }

    public InetAddress getRemoteAddress() { ... }

    public void setRemoteAddress(InetAddress remoteAddress) { ... }

    public Security getSecurity() { ... }

    public static class Security {

        private String username;

        private String password;

        private List<String> roles = new ArrayList<>(Collections.singleton("USER"));

        public String getUsername() { ... }

        public void setUsername(String username) { ... }

        public String getPassword() { ... }

        public void setPassword(String password) { ... }

        public List<String> getRoles() { ... }

        public void setRoles(List<String> roles) { ... }

    }
}

上面的類定義了下列屬性:

  • foo.enabled,預設值false
  • foo.remote-address,可以由String強轉而來
  • foo.security.username,內部類security
  • foo.security.password
  • foo.security.rolesString的集合型別

也可以使用@EnableConfigurationProperties註解來註冊配置資訊

@Configuration
@EnableConfigurationProperties(FooProperties.class)
public class MyConfiguration{
}

當使用@ConfigurationPropertiesbean註冊這種方式時,這個bean使用的名稱類似<prefix>-<fqn><prefix>代表環境,<fqn>是bean的全限定名,如果沒有指定<prefix>,則全限定名被使用,例如 foo-com.example.FooProperties 儘管配置檔案載入會自動建立一個FooPropertiesbean,但是建議自己建立它,使用@ConfigurationProperties註解標註,

@Component
@ConfigurationProperties(prefix="foo")
public class FooProperties {

    // ... see above

}
# application.yml

foo:
    remote-address: 192.168.1.1
    security:
        username: foo
        roles:
          - USER
          - ADMIN

# additional configuration as required
@Service
public class MyService {

    private final FooProperties properties;

    @Autowired
    public MyService(FooProperties properties) {
        this.properties = properties;
    }

     //...

    @PostConstruct
    public void openConnection() {
        Server server = new Server(this.properties.getRemoteAddress());
        // ...
    }

}

24.7.1第三方配置

使用@ConfigurationProperties在public型別有@Bean註解的方法上,在繫結配置值給第三方元件上非常有用

@ConfigurationProperties(prefix = "bar")
@Bean
public BarComponent barComponent() {
    ...
}

24.7.2非嚴格的資料繫結

Spring Boot使用一些非嚴格的策略繫結Environment屬性值到@ConfigurationPropertiesbean中,因此在Environment的屬性名和bean的屬性名之間保持精確的匹配,通常使用中劃線轉換為駝峰命名方式,例如context-path對應contextPath,或者使用PORT對應port,這些都是可以的 例如:@ConfigurationProperties類:

@ConfigurationProperties(prefix="person")
public class OwnerProperties {

    private String firstName;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

}

下面的這些屬性名都可以被使用:

屬性 描述
person.firstName 標準的駝峰命名法
person.first-name 中劃線方式,在.properties.yml檔案都推薦使用
person.first_name 下劃線方法
PERSON_FIRST_NAME 全大寫方式,系統環境變數建議使用

24.7.3 屬性轉換

Spring會嘗試強制轉換屬性值到@ConfigurationPropertiesbean中定義的型別,你可以提供ConversionServicebean或者定義屬性編輯器CustomEditorConfigurer或者定義Converters(@ConfigurationPropertiesBinding)來自定義型別轉換方式

24.7.4 @ConfigurationProperties校驗

Spring Boot使用@Validated註解嘗試校驗@ConfigurationProperties,你可以在配置類上使用JSR-303的javax.validation約束註解,例如:

@ConfigurationProperties(prefix="foo")
@Validated
public class FooProperties {

    @NotNull
    private InetAddress remoteAddress;

    // ... getters and setters

}

為了校驗屬性,你必須在需要校驗的欄位上新增@Valid來觸發校驗,例如:

@ConfigurationProperties(prefix="connection")
@Validated
public class FooProperties {

    @NotNull
    private InetAddress remoteAddress;

    @Valid
    private final Security security = new Security();

    // ... getters and setters

    public static class Security {

        @NotEmpty
        public String username;

        // ... getters and setters

    }

}

建立一個bean呼叫configuratonPropertiesValidator來自定義校驗邏輯,@Bean的方法應該是static的, 配置屬性的校驗發生在應用生命週期的早期,@Bean的靜態方法允許bean不例項化@Configuration類而建立,這會避免一些安裝問題。

24.7.5 @ConfigurationProperties vs @Value

@Value是容器的核心特性,而且它不提供安全型別配置屬性。下表是@ConfigurationProperties@Value的對比

如果在你自己的元件內定義了一組配置屬性,建議使用@ConfigurationProperties註解的POJO來組織它們,請注意因為@Value不支援寬鬆資料繫結,所以不建議使用它來提供系統環境變數。 當你在@Value中使用SpEL表示式,這些表示式不會在配置檔案中被處理。

25 環境配置檔案

Spring Profiles提供分離配置檔案的方法,使得在某一環境只有一個生效,任何使用@Component或者@Configuration都可以使用@Profile來限制它載入的環境

@Configuration
@Profile("production")
public class ProductionConfiguration {

    // ...

}

也可以使用application.propertiesspring.profiles.active屬性配置它

spring.profiles.active=dev,hsqldb

或者通過命令列指定 --spring.profiles.active=dev,hsqldb

25.1 新增活動配置

spring.profiles.active和其他的屬性配置一樣有相關的順序,PropertySource越高載入越早,意思是你在application.properties中配置了啟用的配置,但是可以使用命令列來替換它 有時候給啟用的配置新增一些特殊的配置屬性比直接替換已啟用的配置更好,spring.profiles.include可以達到此目的,SpringApplication也提供了操作的API,setAdditionalProfiles() 例如,--spring.profiles.active=prodproddbprodmq也會被啟用

---
my.property: fromyamlfile
---
spring.profiles: prod
spring.profiles.include:
  - proddb
  - prodmq

25.2 編碼設定啟用配置

可以使用SpringApplication.setAdditionalProfiles(...)來設定啟用的配置,也可以使用ConfigurableEnvironment介面來啟用配置

25.3 啟用的配置

啟用的配置可以是application.propertiesapplication.yml或者使用@ConfigurationProperties註解的檔案

26 日誌

Spring Boot 使用Commons Logging作為內嵌的日誌元件,但是也留有自定義實現的介面。預設使用Java Util LoggingLog4J2Logback等配置,日誌可以配置為控制檯輸出或者檔案輸出。 預設情況下,如果你使用Starters,Logback會被預設使用 Java有很多的日誌元件,不過不用擔心,通常不用特殊設定,Spring Boot都可以工作的很好

26.1 日誌格式化

Spring Boot預設的日誌:

2014-03-05 10:57:51.112  INFO 45469 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.52
2014-03-05 10:57:51.253  INFO 45469 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2014-03-05 10:57:51.253  INFO 45469 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1358 ms
2014-03-05 10:57:51.698  INFO 45469 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2014-03-05 10:57:51.702  INFO 45469 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]

它包含的內容:

  • Date and Time日期和時間 – 可分類和毫秒精度
  • Log Level日誌級別 – ERRORWARNINFOTRACE
  • Process ID 程序ID
  • ---分隔符,分隔日誌訊息
  • Thread name 執行緒名稱 – 方括號括起來的
  • Logger name 日誌元件名稱–通常是一個類名
  • log message 日誌訊息

Logback沒有FATAL級別,使用ERROR替代

26.2 控制檯輸出

日誌預設是輸出到控制檯的,預設級別是ERRORWARNINFO,使用--debug開啟"debug"除錯模式 $ java -jar myapp.jar --debug 也可以在application.properties中指定debug=true來開啟除錯模式 當開啟除錯模式時,會輸出內嵌容器、Hibernate和SpringBoot本身的日誌。 使用--trace或者application.properties中設定trace=true設定"trace"跟蹤模式,它會列印內嵌容器、Hibernate的元資料和Spring的全部資訊

26.2.1 日誌程式碼顏色

如果你的控制檯支援ANSI,則輸出程式碼顏色使日誌更易讀。設定spring.output.ansi.enabled來開啟顏色支援 程式碼顏色使用%clr設定,例如: %clr(%5p) 顏色對應列表:

級別 顏色
FATAL Red(紅色)
ERROR Red(紅色)
WARN Yellow(黃色)
INFO Green(綠色)
DEBUG Green(綠色)
TRACE Green(綠色)

使用自定義配置覆蓋預設: %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){yellow} 顏色和樣式支援列表:

  • blue
  • cyan
  • faint
  • green
  • magenta
  • red
  • yellow

26.3 輸出到檔案

預設Spring Boot僅僅將日誌輸出到控制檯,在application.properties中設定logging.file或者logging.path屬性使日誌寫入到檔案中 可以使用的logging.*屬性列表:

logging.file logging.path 例子 描述
(none) (none) 只輸出到控制檯
Specific file指定檔案 (none) my.log 寫入到指定檔案,可以是內部路徑或外部路徑檔案
(none) Specific directory 指定目錄 /var/log 寫入到指定目錄下的spring.log檔案中

預設情況下日誌檔案單個最大10MB,預設輸出ERRORWARNINFO訊息

26.4 日誌級別

所有支援的日誌元件都可以通過在application.properties中設定logging.level.*=LEVEL來設定日誌級別,LEVEL支援TRACEDEBUGINFOWARNERRORFATALOFFroot日誌可以通過logging.level.root配置,例如application.properties中配置如下:

logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR

26.5 自定義日誌配置

增加日誌元件的依賴,在classpath的根目錄下增加對應的配置檔案,或者指定logging.config指定位置,就可以實現自定義日誌元件配置 可以通過設定org.springframework.boot.logging.LoggingSystem強迫使用某一個日誌元件,這個屬性的值是一個完整的LoggingSystem實現類,也可以使用none來禁用日誌 不同日誌元件載入的不同配置:

日誌元件 定義檔案
Logback logback-spring.xmllogback-spring.groovylogback.xmllogback.groovy
Log4j2 log4j2-spring.xml或者log4j2.xml
JDK(Java Util Logging) logging.properties

Spring環境變數屬性與系統屬性對應列表

Spring環境變數 系統屬性 備註
logging.exception-conversion-word LOG_EXCEPTION_CONVERSION_WORD 單詞轉換異常
logging.file LOG_FILE 預設配置檔案定義
logging.path LOG_PATH 預設配置檔案路徑定義
logging.pattern.console CONSOLE_LOG_PATTERN 控制檯輸出設定,(僅 logback支援)
logging.pattern.file FILE_LOG_PATTERN 檔案輸出設定,(僅logback支援)
logging.pattern.level LOG_LEVEL_PATTERN 日誌輸出級別,預設%5p,(僅logback支援)
PID PID 當前程序ID

26.6 Logback擴充套件

Spring Boot支援一系列的Logback擴充套件,可以在logback-spring.xml配置檔案中配置 不能在logback.xml中配置它,因為它載入的太早,你需要使用logback-spring.xml或者在logging.config中定義的檔案中定義 不能使用Logback的掃描配置,如果你這樣做,就會報錯

ERROR in [email protected]:71 - no applicable action for [springProperty], current ElementPath is [[configuration][springProperty]]
ERROR in [email protected]:71 - no applicable action for [springProfile], current ElementPath is [[configuration][springProfile]]

26.6.1 特殊配置

<springProfile>用來配置特殊的配置

<springProfile name="staging">
    <!-- configuration to be enabled when the "staging" profile is active -->
</springProfile>

<springProfile name="dev, staging">
    <!-- configuration to be enabled when the "dev" or "staging" profiles are active -->
</springProfile>

<springProfile name="!production">
    <!-- configuration to be enabled when the "production" profile is not active -->
</springProfile>

26.6.2 環境屬性

<springProperty>配置環境屬性

<springProperty scope="context" name="fluentHost" source="myapp.fluentd.host"
        defaultValue="localhost"/>
<appender name="FLUENT" class="ch.qos.logback.more.appenders.DataFluentAppender">
    <remoteHost>${fluentHost}</remoteHost>
    ...
</appender>

未完待續。。。