本节介绍SpringBoot的细节。这里你可以了解到你想使用和定制的SpringBoot的关键功能。如果你还没有准备好,建议你先读Spring Boot 开始(官网文档翻译)_LookOutThe的博客-CSDN博客和使用SpringBoot(官方文档翻译)_LookOutThe的博客-CSDN博客_springboot使用,这样你会有一定的基础。
1.SpringApplication
SpringApplication类提供了一个便捷的方式来从main()方法启动项目。你可以委托给SpringApplication.run静态方法,如下:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
当你的项目启动,你会看到和下面相似的日志:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: v2.5.6
2021-02-03 10:33:25.224 INFO 17321 --- [ main] o.s.b.d.s.s.SpringAppplicationExample : Starting SpringAppplicationExample using Java 1.8.0_232 on mycomputer with PID 17321 (/apps/myjar.jar started by pwebb)
2021-02-03 10:33:25.226 INFO 17900 --- [ main] o.s.b.d.s.s.SpringAppplicationExample : No active profile set, falling back to default profiles: default
2021-02-03 10:33:26.046 INFO 17321 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2021-02-03 10:33:26.054 INFO 17900 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-02-03 10:33:26.055 INFO 17900 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.41]
2021-02-03 10:33:26.097 INFO 17900 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2021-02-03 10:33:26.097 INFO 17900 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 821 ms
2021-02-03 10:33:26.144 INFO 17900 --- [ main] s.tomcat.SampleTomcatApplication : ServletContext initialized
2021-02-03 10:33:26.376 INFO 17900 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2021-02-03 10:33:26.384 INFO 17900 --- [ main] o.s.b.d.s.s.SpringAppplicationExample : Started SampleTomcatApplication in 1.514 seconds (JVM running for 1.823)
默认展示info级别的日志,包含一些启动信息,比如启动项目的用户。如果你想打印其他级别的日志信息,你也可以设置,这个后面会说。项目版本号取决与主类使用的版本号。启动日志信息也可以通过设置spring.main.log-startup-info为false来关闭。也会关闭项目active profiles的记录。(不会记录当前启动的是那个配置文件)
你可以重写SpringApplication的logStartupInfo(boolean)方法来添加额外的日志。
1.1 启动失败
如果启动失败,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.
Spring Boot提供很多的FailureAnalyzer实现类,你也可以添加你自己的。
如果没有对应的FailureAnalyzer处理处理异常。你也可以输出完整的情况去理解发生了什么错误,这样做你需要开启debug模式或者开启debug级别日志。
比如开启java -jar启动的项目可以这样开启debug模式:
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
关于日志的开启,日志小节会讲。
1.2 懒初始化(延迟初始化)
SpringApplication允许项目懒初始化。当开启懒初始化,beans(spring管理的对象)是在使用的时候才会创建,而不是项目启动的时候。这样,通过懒初始化可以减少项目的启动时间。在web项目中,使用懒初始化可能会造成接收到一个http请求的时候,很多web相关的bean都没有创建。
懒初始化的一个坏处是会项目中的问题会延迟被发现。如果一个错误的配置类bean被延迟加载,这个错误在项目启动的时候不会发生,只有在这个bean被初始化的时候才会发生。而且还得确保JVM有足够的内存去容纳这些延迟加载的bean。综上原因,懒初始化默认是关闭的。建议在开启懒初始化前对jvm的堆大小进行微调。
懒初始化可以用编程方式开启,使用SpringApplicationBuilder的lazyInitialization方法或者SpringApplication的setLazyInitialization方法。或者也可以使用spring.main.lazy-initialization属性开启:
spring.main.lazy-initialization=true
如果你想在使用懒初始化的时候让某些bean禁止懒初始化,你可以使用@Lazy(false)来明确的设置他们的lazy属性为false。
1.3 定制化横幅(Banner)
在classpath下添加一个banner.txt文件或者通过spring.banner.location配置来定位这样的文件可以修改项目启动打印的banner。如果banner.txt不是utf-8编码的,你可以通过spring.banner.charset设置编码。除了banner.txt,你也可以添加一个banner.gif、banner.jpg、banner.png来代替banner.txt。图片将会被转为ASCII形式打印在其他文本类型banner上方。
在banner.txt里面,你可以使用下面的占位符(placeholders):
${application.version} | 你项目的版本号。在MANIFEST.MF文件中声明的。比如Implementation-Version: 1.0 就会打印1.0 |
${application.formatted-version} | 你项目的版本号。在MANIFEST.MF文件中声明的。会格式化后展示(在版本号前面拼接一个v,比如v1.0) |
${spring-boot.version} | 你使用的SpringBoot的版本,比如2.5.6 |
${spring-boot.formatted-version} | 同理;比如v2.4.6 |
| ANSI转移序列的名字;ANSI 转义序列是一种用于控制终端输出的色彩、样式、光标位置以及控制终端行为的特殊字节. |
${application.title} | 你项目的标题,在MANIFEST.MF文件中声明的。比如Implementation-Title: MyApp 就会打印 MyApp |
如果你想使用编码的方式创建一个banner,可以使用SpringApplication.setBanner(…)方法。入参:使用org.springframework.boot.Banner接口,并实现你自己的printBanner()方法。
你也可以通过设置spring.main.banner-mode属性,控制banner在控制台打印、还是日志文件打印,或者直接关闭。
要被打印的banner会被注册为一个单例bean,名字:springBootBanner。
${application.version}
和${application.formatted-version}只会在使用
Spring Boot launchers的时候有用。使用java -cp <classpath> <mainclass>启动一个解压的jar包的时候不会起作用。
1.4 定制SpringApplication
如果默认的SpringApplication不符合你的胃口,你可以通过创建实例并定制化来替代。比如关闭banner,你可以这样做:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.run(args);
}
}
完整配置列表:SpringApplication Javadoc
1.5 Events and Listeners
除了Spring框架常用的event,比如ContextRefreshedEvent。Spring应用还有一些别的events。
一些events在ApplicationContext创建之前触发,所以你不能在这些events里面使用@Bean注册Listener,你可以使用SpringApplication.addListeners(…)方法或者SpringApplicationBuilder.listeners(…)方法来注册。
如果你不想关心应用如何启动,让这些listener自动注册,你可以在你的项目中添加一个META-INF/spring.factories文件,文件中使用org.springframework.context.ApplicationListener这个key来指向你的Listener。比如下面的例子:
org.springframework.context.ApplicationListener=com.example.project.MyListener
当你的项目启动时,events按以下顺序触发:
- ApplicationStartingEvent在项目刚开始运行的时候触发。这个时候除了Listeners和Initialzers注册之外其他代码都没有执行 。
- ApplicationEnvironmentPreparedEvent当SpringContext要使用的Environment准备好后触发,这个时候SpringContext还没创建。
- ApplicationContextInitializedEvent当ApplicationContext准备好以及ApplicationContextInitializers被调用后触发,但是在bean definitions加载之前。
- ApplicationPreparedEvent在上下文刷新前,bean definitions被load之后触发。
- ApplicationStartedEvent在上下文刷新后,application和command-line runners被调用前触发。