跟着官方文档学 SpringBoot 三:spring boot 特性
spring boot 特性
【启动相关】
1. 启动应用
在启动应用类的 main 方法中调用 SpringApplication 的 run():
public static void main(String[] args) { SpringApplication.run(MySpringConfiguration.class, args); }
2. 启动失败
如果应用启动失败了,FailureAnalyzers 会获取错误信息,并得到一个具体解决该问题的办法。
比如,8080 端口被占用,你可能会看到如下信息:
*************************** 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.
如何创建自己的失败分析器?
1)创建一个自定义的失败分析类,继承 AbstractFailureAnalyzer。如果自己无法处理异常问题,可以通过返回 null 来让其他实现类来处理;
2)在 META/spring.factories 文件中注册该类,如下:
org.springframework.boot.diagnostics.FailureAnalyzer=\ com.example.ProjectConstraintViolationFailureAnalyzer
如果需要访问 BeanFactory 或者 Environment,那么自定义的 FailureAnalyzer 可以通过实现 BeanFactoryAware 或者 EnvironmentAware 接口。
3. 定制 Banner
Banner,即应用启动时的图像,默认为 spring boot:
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: v2.0.0.RELEASE
通过在 classpath(比如在 resources 文件夹下) 添加一个 banner.txt 或者 在配置文件中设置 spring.banner.location 属性指定文件位置。如果文件的编码不是 UTF-8,那么需要设置 spring.banner.charset 指定编码。
除了添加文本文件,也可以添加 banner.gif,banner.jpg 或者 banner.png 的图片,或者设置 spring.banner.image.location 属性指定文件位置,图片会被转换为 ASCII 码的表现形式打印。
博主在 resources 下 添加了 banner.png :
启动应用后,显示效果:
延伸:什么是 classpath?
虽然,classpath 这个词翻译为中文,大家都知道,叫做“类路径”,那么究竟什么是类路径呢?想必许多同学和我一样曾经被困扰过。
classpath 指的是程序编译后 classes(类的字节码文件)所在的目录。在程序没有编译前,通常 .java 文件放置于 java 文件夹下(比如 src/main/java/service/UserService.java),而配置文件通常位于 resources 文件夹下(比如 src/main/resources/application.properties)。当程序编译后,java 文件夹下的 .java 文件会变为 target/classes 文夹下的.class 文件,resources 文件夹下的文件也会被置于 classes 文件夹下,此时的 classes 文件夹即项目的 classpath。
如果将 banner.txt 或者 banner.png 直接放置于 src/main/java 文件夹下,由于编译后不在 target/classes 文件夹下,因而是不会生效的。(IntelliJ IDEA 工具编译后的文件都在 target 目录下)
4. 定制 SpringApplication
当你觉得默认的 SpringApplication 无法满足使用时,可以通过创建一个本地(相对于 spring-boot-starter 而言)的实例来定制它。
比如,上一小节的定制 Banner 同样可以通过编程的方式实现:
public static void main(String[] args) { SpringApplication application = new SpringApplication(Example.class); application.setBanner(new MyBanner()); application.run(args); }
也可以关闭它:
public static void main(String[] args) { SpringApplication application = new SpringApplication(Example.class); application.setBannerMode(Banner.Mode.OFF); application.run(args); }
5. 流式 API
通过 SpringApplicationBuilder 对象可以实现链式调用多个方法,并且创建一个分层次的应用上下文环境:
new SpringApplicationBuilder() .sources(Parent.class) .child(Application.class) .bannerMode(Banner.Mode.OFF) .run(args);
在创建分层的 应用上下文时需要注意一些限制,比如 Web 组件必须包含在子上下文中,并且子上下文和父上下文必须使用同一个 Environment。
6. 事件和监听器
一些事件是在 ApplicationContext 创建之前被触发的,因此无法在这些事件上注册 listener 作为一个 @Bean。可以通过 SpringApplication.addListeners() 或者 SpringApplicationBuilder.listeners() 方法进行注册;如果想要这些 listeners 自动注册,而不关心应用的创建方式,可以添加 META-INF/spring.factories 文件,通过如下示例方式注册 listener:
org.springframework.context.ApplicationListener=com.example.project.MyListener
7. Web 环境
SpringApplication 会尝试创建正确类型的 ApplicationContext,默认情况下使用 AnnotationConfigApplicationContext 或者 AnnotationConfigServletWebServerApplicationContext,
这基于正在开发的是否为一个 web 应用。判断一个环境是否为 web 环境的算法是相当简单的,基于几个类是否存在而已。如果想要覆盖它判断环境类型的方式,
可以通过 setWebEnvironment(boolean webEnvironment)设置。通过调用 setApplicationContextClass() 方法可以自己控制 ApplicationContext。在 JUnit 测试环境下使用 SpringApplication时,推荐调用 setWebEnvironment(false) 方法。
8. 访问应用参数
如果需要访问那些被传递进 SpringApplication.run() 方法的参数,可以通过注入一个 org.springframework.boot.ApplicationArguments bean。ApplicationArguments 接口提供了访问原生的 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 环境注册了一个 CommandLinePropertySource。这使得可以通过使用 @Value 注释来注入单个应用程序参数。
9 使用 ApplicationRunner 或者 CommandLineRunner
如果有一些特殊的代码需要在 SpringApplication 启动完成之前运行,那么可以通过实现 ApplicationRunner 或者 CommandLineRunner 接口来完成。这两个接口运行的方式都是一样的,
并且提供单一的 run 方法,run 方法会在 SpringApplication.run() 完成之前被调用。
CommandLineRunner 接口将应用参数当作简单的 string 数组进行访问,如下示例:
import org.springframework.boot.* import org.springframework.stereotype.* @Component public class MyBean implements CommandLineRunner { public void run(String... args) { // Do something... } }如果定义了多个 CommandLineRunner 或者 ApplicationRunner beans,那么它们必须根据特定的顺序被调用。
可以通过额外实现 org.springframework.core.Ordered 接口,或者使用 org.springframework.core.annotation.Order 注解完成顺序调用。
10. 退出应用
每个 SpringApplication 都向 JVM 注册了一个关闭的钩子(hook),以确保在退出的时候优雅地关闭 ApplicationContext 。所有的 Spring 标准生命周期的回调都可以使用,比如 DisposableBean 接口或者 @PreDestroy 注解。
此外,如果希望在 SpringApplication.exit() 被调用前执行一段特定的退出代码(exit code),那么这些 beans 可以通过实现 org.springframework.boot.ExitCodeGenerator 接口完成。
这些特定的退出代码会被传递至 System.exit() 用来作为状态码返回,如下示例:
@SpringBootApplication public class ExitCodeApplication { @Bean public ExitCodeGenerator exitCodeGenerator() { return () -> 42; } public static void main(String[] args) { System.exit(SpringApplication .exit(SpringApplication.run(ExitCodeApplication.class, args))); } }
并且,异常类可以通过实现 ExitCodeGenerator 接口和实现 getExitCode()方法,在异常发生时,可以返回退出代码。
11. 管理员特性
通过指定 spring.application.admin.enabled 属性为 true(false)启用(不启用)管理员相关特性,这会将 SpringApplicationAdminMXBean 暴露在 MBeanServer 平台。可以通过使用这个特性远程管理 spring boot 应用,这对于服务包装实现很有用。
【外部化配置】
springboot 可以外部化配置,使得相同的代码可以适应不同的环境。简单讲,就是从外部的配置文件获取指定值,不写死代码。
使用 properties 文件、YAML 文件、环境变量、命令行参数这几种方式进行配置。这些配置的属性值可以通过 @Value 注解直接注入到 bean 中,可以通过 Spring 的 Environment 接口实现类来访问,
或者通过 @ConfigurationProperties 绑定到结构化对象。
为了实现属性值的合理的覆盖(因为配置方式有多种,可能存在键重复值覆盖),springboot 使用了一种特殊的顺序。属性将按以下顺序读取:
1. Devtools 全局设置。(当开启了 devtools 的情况下,在 ~/ .spring-boot-devtools.properties 配置)
2. 测试类中 @TestPropertySource 注解中的属性值
3. 测试类中 @SpringBootTest#properties 注解中的属性值
4. 命令行参数
5. SPRING_APPLICATION_JSON 的属性值(内嵌在环境变量或系统属性中的JSON)
6. ServletConfig 初始化参数
7. ServletContext 初始化参数
8. 来自 java:comp/env 的 JNDI 属性
9. Java 系统属性值(通过 System.getProperties() 获取的值)
10. 操作系统环境变量
11. RandomValuePropertySource 中有属性值的,并且符合 random.* 格式
12. 没被打进 jar 包的 profile-specific 应用属性(application-{profile}.properties 和 YAML 变量)
13. 被打进 jar 包的应用属性(application-{profile}.properties 和 YAML 变量)
14. 没被打进 jar 包的应用属性(application-{profile}.properties 和 YAML 变量)
15. 被打进 jar 包的应用属性(application-{profile}.properties 和 YAML 变量)
16. 在 @configuration 类上的 @PropertySource 注解属性
17. 默认属性(通过设置 SpringApplication.setDefaultProperties 指定的)
在举具体的示例之前,推荐先写一个使用了 name 属性值的组件(@Component),如下:
import org.springframework.stereotype.* import org.springframework.beans.factory.annotation.* @Component public class MyBean { @Value("${name}") private String name; // ... }
在 classpath (比如 resources 资源文件夹)中添加一个“application.properties”属性文件,在文件中指定 name 的值,如 name=Lina。
对于一次性测试,可以在命令行中进行指定,比如:
java -jar app.jar --name="Spring"
SPRING_APPLICATION_JSON 的属性值可以通过环境变量的方式应用于命令行:
1. 在 UNIX shell 中可以使用如下命令:
$ SPRING_APPLICATION_JSON='{"acme":{"name":"test"}}' java -jar myapp.jar该命令表示 在 spring 中 acme.name 对应的属性值为 test。
2. 在系统属性(System property)中将 JSON 作为 spring.application.json 使用:
$ java -Dspring.application.json='{"name":"test"}' -jar myapp.jar3. 通过使用命令行参数来使用 JSON:
$ java -jar myapp.jar --spring.application.json='{"name":"test"}'