Spring Boot 官方文档学习(二)特点

一、SpringApplication

banner,就是启动时输出的信息,可以在classpath下添加 banner.txt,或者设置 banner.location 来指向特定的文件。(默认编码utf-8,或者通过banner.charset指定)
除了txt,你还可以使用 banner.gif (jpg / png),或者设定 banner.imgage.location。
通过设置 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,以下面的顺序发送:
  1. ApplicationStartedEvent 应用启动时发送,是除了注册监听器和初始化之外最早的。
  2. ApplicationEnvironmentPreparedEvent 创建context之前,已知道context需要使用的Environment时。
  3. ApplicationPreparedEvent 发生在context刷新之前,但在bean 定义加载之后。
  4. ApplicationReadyEvent 发生在刷新和任何相关回调被处理之后,表明应用已准备好响应请求了。
  5. 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下的优先级比默认的高。具体如下:
  1. @TestPropertySource annotations on your tests.
  2. Command line arguments.
  3. Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property)
  4. ServletConfig init parameters.
  5. ServletContext init parameters.
  6. JNDI attributes from java:comp/env.
  7. Java System properties (System.getProperties()).
  8. OS environment variables.
  9. A RandomValuePropertySource that only has properties in random.*.
  10. Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants)
  11. Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants)
  12. Application properties outside of your packaged jar (application.properties and YAML variants).
  13. Application properties packaged inside your jar (application.properties and YAML variants).
  14. @PropertySource annotations on your @Configuration classes.
  15. 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 中,所以,后面的值可以使用前面的值,使用方法就是占位符。如下:
  1. app.name=MyApp
  2. app.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.activeEnvironment 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

注意:官方建议使用 -spring的文件名,否则Spring不能完全控制log初始化(因为初始化太早)。

警告:直接运行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。
291 Comments

Add a Comment

邮箱地址不会被公开。 必填项已用*标注