一、SpringApplication
banner,就是啟動時輸出的信息,可以在classpath下添加 banner.txt,或者設置 banner.location 來指向特定的文件。(默認編碼utf-8,或者通過banner.charset指定)
除了txt,你還可以使用 banner.gif (jpg / png),或者設定 banner.imgage.location。
下面是默認的banner(忽略吧,沒意義的東西):
banner變量,只有應用相關的信息,略,見pdf。
還可以使用通過 SpringApplication.setBanner(…) 來設置。通過實現 org.springframework.boot.Banner 接口,可以實現自己的 printBanner() 。
通過設置 spring.main.banner-mode 來決定是否在
System.out
(console) 上顯示banner。使用配置的logger (log)或者全不用 (off)。
輸出的banner會被注冊成一個單例的bean,名字springBootBanner。
如果,你想創建一個分層次的ApplicationContext (多個context,有父子關系),可以使用
SpringApplicationBuilder 。它可以讓你鏈式調用方法,並且設置父子關系。如下:
new SpringApplicationBuilder() .bannerMode(Banner.Mode.OFF) .sources(Parent.class) .child(Application.class) .run(args);
SpringApplicationBuilder使用起來有一些限制,詳見javadoc。
Application事件和監聽器
除了Spring框架的事件(如ContextRefreshedEvent)之外,SpringApplication還提供了一些額外的事件。
但是,有些事件是在ApplicationContext創建之前,所以無法通過@Bean形式注冊監聽器。可以通過SpringApplication.addListeners(...) 或者 SpringApplicaitonBuilder.listeners(...) 來注冊。
另外,如果想以與application創建形式無關的方式來注冊listeners,可以這樣做:創建一個 META-INF/spring.factories 文件。內容如下:
org.springframework.context.ApplicationListener=com.example.project.MyListener
多個監聽器,應該用逗號連接吧???
Application Events,以下面的順序發送:
ApplicationStartedEvent 應用啟動時發送,是除了注冊監聽器和初始化之外最早的。ApplicationEnvironmentPreparedEvent 創建context之前,已知道context需要使用的Environment時。ApplicationPreparedEvent 發生在context刷新之前,但在bean 定義加載之后。ApplicationReadyEvent 發生在刷新和任何相關回調被處理之后,表明應用已准備好響應請求了。ApplicationFailedEvent 發生在啟動期間發生異常時。
沒必要使用這些事件,但是了解一下還是挺有用的。Spring Boot內部使用這些事件來處理很多任務。
Web 環境
SpringApplication 會試圖創建正確的 ApplicationContext。默認的,使用 AnnotationConfigApplicationContext 或者 AnnotationConfigEmbeddedWebApplicationContext ,這取決於是否web應用。
可以使用覆蓋 setWebEnvironment(boolean webEnvironment) 默認設置。
也可以使用 setApplicationContextClass(…) 來控制 ApplicationContext 的類型。
注意:當在JUnit環境下使用SpringApplication時,通常需要設置 setWebEnvironment(false) 。
訪問應用的參數
如何訪問傳遞給SpringApplication.run(...) 的參數?
你可以注入一個 org.springframework.boot.ApplicationArguments bean。這是一個接口,提供了 String[] 和 option/non-option 參數形式。
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還會在Spring Environment中注冊一個 CommandLinePropertySource 。它可以讓你使用 @Value 注解注入application argument。
就是,如果有argument --larry.name=larry,那么可以使用@Value("${larry.name}"}String larryName;
ApplicationRunner or CommandLineRunner
如果想在SpringApplication啟動后執行一些特定的代碼,可以讓這些代碼實現
ApplicationRunner
or CommandLineRunner 接口。二者都提供了一個run(),可以在SpringApplication.run(...) 完成之前被調用。
區別:
CommandLineRunner 只提供對傳遞參數的默認訪問形式 String[],而
ApplicationRunner 則使用了上面提到的 ApplicationArguments 接口。
import org.springframework.boot.* import org.springframework.stereotype.* @Component public class MyBean implements CommandLineRunner { public void run(String... args) { // Do something... } }
如果,定義了多個
CommandLineRunner
or ApplicationRunner beans,那么可以通過實現 org.springframework.core.Ordered 接口或使用 org.springframework.core.annotation.Order 注解來控制加載順序。
Application exit
每一個 SpringApplication 都注冊了一個shutdown hook with JVM,以確保 ApplicationContext 順利的關閉。所有的Spring生命周期中的回調(如 DisposableBean 接口,或者 @PreDestroy 注解)都可以使用。
另外,如果想在應用退出時返回特定的exit code,那beans可以實現 org.springframework.boot.ExitCodeGenerator 接口。
個人經驗:同樣可以使用@Order控制順序,只不過相反。
個人經驗:使用@Order控制的順序,不能打破大的順序。例如上面(ApplicationRunner or CommandLineRunner)的順序,永遠在SpringApplication啟動完成之前調用。
Admin features(略)
Externalized Configuration(需要認真看看)
外來配置?就是說,通過設定這些配置,可以在不同的工作環境下運行相同的代碼達到相同的目的。
Spring Boot支持的:properties文件、yaml文件、environment 變量、命令行參數。
然后,可以通過 @Value 注解注入到bean中,或者通過Spring 的 Environment 訪問,或者通過 @ConfigurationProperties 綁定到結構化對象中。
個人經驗:@Value 的工作是在SpringApplication啟動完成
之后進行的,在此之前值為null。
注意:不同方式的配置的優先級不一樣。基本上,除了測試情況外,命令行參數優先級最高。尤其要注意指定profile下的優先級比默認的高。具體如下:
@TestPropertySource annotations on your tests.Command line arguments.Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property)ServletConfig init parameters.ServletContext init parameters.JNDI attributes from java:comp/env.Java System properties (System.getProperties()).OS environment variables.A RandomValuePropertySource that only has properties in random.*.Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants)Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants)Application properties outside of your packaged jar (application.properties and YAML variants).Application properties packaged inside your jar (application.properties and YAML variants).@PropertySource annotations on your @Configuration classes.Default properties (specified using SpringApplication.setDefaultProperties).
Configuring random values
RandomValuePropertySource 用於注入隨機數值,它可以生成int、long、uuid 或者 字符串。如下:
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]}
Accessing command line properties
默認,SpringApplication會將任何命令行參數(以--開頭,如--server.port=8900)轉成一個property,並添加到Spring Environment中。
再次強調:命令行參數的優先級最高。
如果不想添加到Spring Environment中,你可以禁用它們: SpringApplication.setAddCommandLineProperties(false) 。
關於application.properties文件
SpringApplication默認從以下地址加載,並添加到Spring Environment 中。
/config / classpath/ classpath/config
注意,優先級從上往下依次降低。
如果不想使用默認的名字,可以自行指定(兩種方式):
java -jar myproject.jar --spring.config.name=myproject java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
注意,默認的加載地址
永遠有效,但可以添加新的,且新的地址的優先級更高。
注意,多數系統的環境變量不允許使用點分隔的鍵名,可以使用下划線代替。如: SPRING_CONFIG_NAME 代替 spring.config.name 。
另外,如果在容器中執行,還可以使用JNDI properties或者 Servlet Context初始化參數。
Profile-specific properties
在 application.properties 之外,還會加載 application-{profile}.properties 。由於 Environment 提供了一個默認的profile,所以,默認還會加載 application-default.properties 。
奇怪,這什么意思:
If you have specified any files in spring.config.location, profile-specific variants of those files will not be considered. Use directories in `spring.config.location` if you also want to also use profile-specific properties.
properties中的占位符
application.properties 中的值是按順序加載到已有的 Environment 中,所以,后面的值可以使用前面的值,使用方法就是占位符。如下:
app.name=MyAppapp.description=${app.name} is a Spring Boot application
可以利用該技術創建短的變量?
YAML是JSON的超集!(略)
classpath中只要有SnakeYAML 庫,SpringApplication就可以自動支持YAML。
而,Starters默認就含有SnakeYAML 庫。
類型安全的Configuration Properties
這里的意思是說,通過Java類來確保類型安全,但
值還是要在YAML中提供!!!
@ConfigurationProperties(prefix="connection") public class ConnectionProperties { private String username; private InetAddress remoteAddress; // ... getters and setters }
那么,@Value("${property}") 和@ConfigurationProperties 的區別? 暫略。
注意:
通過 @ConfigurationProperties 類進行的properties設置,需要在 @Configuration 類上開啟 @EnableConfigurationProperties 注解才行,而且,需要手動添加 @ConfigurationProperties
類,如下:
@Configuration @EnableConfigurationProperties(ConnectionProperties.class) public class MyConfiguration { }
需要注意的是, @ConfigurationProperties 類對應的bean有一個約定好的名字:
<prefix>-<fqn> 。fqn是full qualified name。
前面的例子,對應的名字是: connection-com.example.ConnectionProperties ,這里假定它在包 com.example 中。
但是,@ConfigurationProperties 類對應的bean還有一個默認的名字!!!只是,不建議在environment之外使用而已。
除了上面的紅字部分,由於 @EnableConfigurationProperties 注解 會被自動應用到項目中,所以,只要確保 @ConfigurationProperties 類 是一個bean(即@Component),就會被自動添加到 Environment 。如下:
@Component //確保是一個bean即可! @ConfigurationProperties(prefix="connection") public class ConnectionProperties { // ... getters and setters of username and remoteAddress, and so on }
這種形式的配置可以和YAML配置完美的配合。為什么要配合?
因為上面只是類型安全,沒有值!!!
# application.yml
connection:
username: admin
remoteAddress: 192.168.1.1
# additional configuration as required
個人經驗:奇怪,為什么STS提示我在pom中添加spring-boot-starter-configxxxxx ?
提示:使用 @ConfigurationProperties,還可以生成meta-data文件,以供IDE使用。
第三方配置?
@ConfigurationProperties 還可以用於 @Bean 方法上。如下:
@ConfigurationProperties(prefix = "foo") @Bean public FooComponent fooComponent() { ... }
這樣,就是給bean加一個前綴,這個bean就可被用作ConfigurationProperties了!!!! 貌似也沒別的了,一個bean而已。
靈活的綁定:是指對名字的匹配
例如:
@ConfigurationProperties(prefix="person") public class OwnerProperties { private String firstName; public String getFirstName() { return this.firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } }
這里的 firstName 可以綁定如下內容:
person.firstName |
Standard camel case syntax. |
person.first-name |
Dashed notation, recommended for use in.properties and .yml files. |
person.first_name |
Underscore notation, alternative format for use in .properties and .yml files. |
PERSON_FIRST_NAME |
Upper case format. Recommended when using a system environment variables. |
Properties conversion,轉換,類似SpringMVC的轉換
如果要自定義類型轉換,三種方式:創建一個 ConversionService bean,或者創建一個 property editors(通過 CustomEditorConfigurer bean),或者創建一個 Converters (@ConfigurationPropertiesBinding)。
注意:這個bean在應用早期被調用,所以,注意限制它的依賴!
@ConfigurationProperties validation
Spring Boot默認使用JSR-303去校驗,所以可以使用JSR-303的注解。如下:
@ConfigurationProperties(prefix="connection") public class ConnectionProperties { @NotNull private InetAddress remoteAddress; // ... getters and setters }
如果有嵌套屬性,需要使用@Valid來觸發校驗。如:
@ConfigurationProperties(prefix="connection") public class ConnectionProperties { @NotNull @Valid private RemoteAddress remoteAddress; // ... getters and setters public static class RemoteAddress { @NotEmpty public String hostname; // ... getters and setters } }
也可以使用自定的Spring Validator,bean id是 configurationPropertiesValidator 即可。
注意: spring-boot-actuator 模塊有一個端點,對外暴露了所有的 @ConfigurationProperties beans。瀏覽器中訪問 /configprops 即可。也可以使用相應的JMX端點???
個人經驗:其實還有很多地址,詳見啟動信息。如下:
@Value("${property}") 和@ConfigurationProperties 的區別
@Value 是core container的feature。不支持靈活綁定,不支持Meta-data。但支持spELl。
@ConfigurationProperties 則支持靈活綁定,支持Meta-data。但不支持spELl。
官方指導里
推薦使用后者。
Profiles
@Profile 可以用於 @Component 或 @Configuration 。
使用
spring.profiles.active
Environment property 來指定運行時的 profile 。如:
#application.properties spring.profiles.active=dev,hsqldb #command line argument --spring.profiles.active=dev,hsqldb
有時候,添加profile 比替換profile 更有用。
spring.profiles.include property 可以做到無條件的添加profile。
SpringApplication也提供了API來添加profile: setAdditionalProfiles() 。
還可以使用 Spring的 ConfigurableEnvironment 接口(實驗了下,太麻煩,不建議使用)。
問題:@Profile在類上和在方法上,是怎么結合的???怎么出問題了。
Logging
Spring Boot 使用JCL接口,但未指定實現。默認的實現包括JUL、Log4j2、Logback。均已設置console輸出。
如果使用Starter模塊,則使用Logback。
Log Level:ERROR, WARN, INFO, DEBUG or TRACE
注意,Logback沒有FATAL,如果設置了FATAL,會被映射成ERROR。
開啟debug模式:--debug,或者在 application.properties:debug=true。
注意,是debug模式,不是DEBUG Level。
彩色輸出
終端支持ANSI才行,不過現在還有不支持的嗎?
需要設置 spring.output.ansi.enabled 。
STS中以Spring Boot Application啟動時,應該默認設置了。
問題是,為什么我直接以Java Application啟動就不行?-- 因為沒有設置顏色。囧~~
File output
默認Log只會ouput到console。如果想輸出到File,應該設置
logging.file 或者
logging.path
property 。
注意:輸出文件大小到達10 Mb時,會重新開始?
注意:logging系統是在應用的早期初始化的,所以,不能在通過 @PropertySource 加載的文件中配置。
注意:logging properties 與實際的logging系統無關,所以,Spring Boot不會管理具體的配置文件,如 logback.configurationFile 或 logback.xml 。
會加載,會執行,但與Spring Boot無關,是logging系統自己的東西。
Log Levels
所有Spring Boot支持的logging系統,都可以在Spring Environment 中設置(如application.properties),格式:logging.level.*=LEVEL。
其中,LEVEL可以是TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF。
root logger可以使用 logging.level.root 設置。如下:
logging.level.root=WARN logging.level.org.springframework.web=DEBUG logging.level.org.hibernate=ERROR
自定義log配置
可以使用不同的logging系統,
只要在classpath中添加相應的jars即可。更進一步,還可以在classpath提供一個相應的配置文件,或者在一個指定的位置(需要使用 logging.config 來指定)。
也可以使用一個特定的logging系統,使用 org.springframework.boot.logging.LoggingSystem 來指定,注意,該鍵對應的值是具體logging實現的全路徑,如為none,則默認完全禁用Spring Boot的logging配置。
再次提醒:logging系統初始化較早,不能使用 @Configuration 里的 @PropertySources 來控制。
根據不同的logging實現,加載不同的配置文件。如下:
| Logback | logback-spring.xml, logback-spring.groovy, logback.xml or logback.groovy |
| Log4j2 | log4j2-spring.xml or log4j2.xml |
| JDK (Java Util Logging) |
logging.properties |
警告:直接運行fat jar時,JUL會有問題,建議避免使用它。
個人問題: Spring Environment 和 System properties 什么關系?為什么書上說一些properties會從前者傳到后者,以幫助自定義?
| Spring Environment | System Property | Comments |
logging.exception-conversion-word |
LOG_EXCEPTION_CONVERSION_WORD |
The conversion word that’s used when logging exceptions.異常?例外? |
logging.file |
LOG_FILE |
Used in default log configuration if defined. |
logging.path |
LOG_PATH |
Used in default log configuration if defined. |
logging.pattern.console |
CONSOLE_LOG_PATTERN |
The log pattern to use on the console (stdout). (Only supported with the default logback setup.) 僅支持默認logback設置。 |
logging.pattern.file |
FILE_LOG_PATTERN |
The log pattern to use in a file (if LOG_FILE enabled). (Only supported with the default logback setup.) 僅支持默認logback設置。 |
logging.pattern.level |
LOG_LEVEL_PATTERN |
The format to use to render the log level (default %5p).(Only supported with the default logback setup.) 僅支持默認logback設置。 |
PID |
PID |
The current process ID (discovered if possible and when not already defined as an OS environment variable). |
注意,如果要使用占位符,應該使用Spring Boot的,而非Spring的。
例子就是Logback的分隔符,應該用“:”,而非“:-”。
提示:SB包含了Logback的大量擴展,用於協助配置。可以在 logback-spring.xml 中使用它們。
注意:
不能在
logback.xml
中使用這些擴展,因為它被加載的太早了。
Profile-specific Configuration (logging)
可以在 <configuration> 內部使用 <springProfile>,然后在 name 屬性里設置profiles。如下:
<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>
<springProperty> 標簽可以使用Spring Environment 中的properties。
<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>
關鍵:scope、source、defaultValue。
