【更新中】本文大部分内容翻译自官方文档https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/html/spring-boot-features.html
文章目录
1.Spring应用程序
The SpringApplication
类提供了一种方便的方法来引导从main()
方法启动的Spring应用程序。你可以委托给SpringApplication.run
方法,如下所示:
public static void main(String[] args) {
SpringApplication.run(Application20200106.class, args);
}
应用程序启动,你应该看到类似以下输出:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: v2.2.2.RELEASE
2019-04-31 13:09:54.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)
2019-04-31 13:09:54.166 INFO 56603 --- [ main] ationConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6e5a8246: startup date [Wed Jul 31 00:08:16 PDT 2013]; root of context hierarchy
2019-04-01 13:09:56.912 INFO 41370 --- [ main] .t.TomcatServletWebServerFactory : Server initialized with port: 8080
2019-04-01 13:09:57.501 INFO 41370 --- [ main] o.s.b.s.app.SampleApplication : Started SampleApplication in 2.992 seconds (JVM running for 3.658)
默认情况下,会显示INFO
日志消息,包括一些相关的启动细节,比如启动应用程序的用户。
如果你需要除了INFO
级别的日志信息,你可以设置日志级别。
应用程序版本是从主程序类包中的实现版本确定的。
设置spring.main.log-startup-info
为false
可以关闭启动日志信息记录。
这还将关闭应用程序活动配置文件的日志记录。
要在启动期间添加额外的日志记录,您可以在SpringApplication
的子类中重写logStartupInfo(boolean)
。
1.1 启动失败
如果您的应用程序启动失败,注册的FailureAnalyzers
将有机会提供专用的错误消息和修复问题的具体操作。
例如,如果您在端口8080上启动一个web应用程序,并且该端口已经在使用,您应该看到类似于以下消息:
***************************
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提供了很多FailureAnalyzers
实现,你也可以创建自定义的故障分析器
如果没有故障分析器能处理异常,你也可以显示完整的条件报告,以便更好地理解出错的原因。您需要为org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
启用debug
属性或启用DEBUG
日志记录。
例如,如果您使用java -jar
运行您的应用程序,您可以启用debug
属性,如下所示:
java -jar myproject-0.0.1-SNAPSHOT.jar --debug
1.2 延迟初始化
开启延迟初始化可以减少应用程序所需的世界,在web应用程序中,启用延迟初始化将导致在接收到HTTP请求之前许多与web相关的bean不会被初始化。
延迟初始化的缺点是较晚得发现应用程序中的问题。如果一个错误配置的bean是延迟初始化的,在启动期间不会出现故障,故障会发生bean被初始化的时候。
还必须注意确保JVM有足够的内存来容纳应用程序的所有bean,而不仅仅是只容纳那些在启动期间初始化的bean。
由于这些原因,延迟初始化默认是禁用的,建议在开启延迟初始化之前对JVM的堆大小进行微调(fine-tuning)。
用编程方式开启延迟初始化:
使用SpringApplicationBuilder
的lazyInitialization
方法:
SpringApplicationBuilder springApplicationBuilder = new SpringApplicationBuilder();
springApplicationBuilder.lazyInitialization(true);
使用SpringApplication
的setLazyInitialization
方法:
SpringApplication springApplication = new SpringApplication(Application20200106.class);
springApplication.setLazyInitialization(true);
配置文件开启延迟从初始化:
使用spring.main.lazy-initialization
属性:
spring.main.lazy-initialization=true
如果你希望一部分bean使用延迟初始化,一部分bean禁用延迟初始化,你可以使用@Lazy(false)
注解。
- lazy = true,表示延迟,默认为true
- lazy = false,表示不延迟
1.3 自定义Banner
在classpath中添加一个banner.txt
文件或者设置spring.banner.location
属性来改变在启动期间打印的banner。
如果文件编码不是UTF-8,需要设置spring.banner.charset
。
除了文本文件,还可以在classpath中添加banner.gif
,banner.jpg
,banner.png
图片文件。或者设置spring.banner.image.location
属性。
图片被转换成ASCII码打印在任何文本banner上方。
在banner.txt
文件中,可以使用下列占位符:
表1 Banner变量
变量 | 说明 |
---|---|
${application.version} |
应用程序的版本号,和MANIFEST.MF 一样的声明。例如,Implementation-Version: 1.0 打印成1.0 。 |
${application.formatted-version} |
应用程序的版本号,和MANIFEST.MF 一样,按照格式显示(用圆括号括起来并且加上前缀v )。如(v1.0) 。 |
${spring-boot.version} |
你在使用的Spring Boot版本,如2.2.2.RELEASE 。 |
${spring-boot.formatted-version} |
你在使用的Spring Boot版本,按照格式显示(用圆括号括起来并且加上前缀v )。如v2.2.2.RELEASE 。 |
${Ansi.NAME} (or ${AnsiColor.NAME}, ${AnsiBackground.NAME}, ${AnsiStyle.NAME}) |
NAME 是ANSI转义码的名称,详情参见AnsiPropertySource 。 |
${application.title} |
应用程序的Title,和MANIFEST.MF 一样。如Implementation-Title: MyApp 打印成MyApp 。 |
如果你想用编程的方式生成一个banner,可以使用SpringApplication.setBanner(…)
。
实现org.springframework.boot.Banner
接口并重写printBanner()
方法。
You can also use the spring.main.banner-mode property to determine if the banner has to be printed on System.out (console), sent to the configured logger (log), or not produced at all (off).
你也可以使用spring.main.banner-mode
属性控制banner是否在System.out
(console
)被打印,或者发送到已配置的日志程序,或者关闭。
打印banner的bean被注册成一个单例bean,名字为:springBootBanner
。
1.4 自定义SpringApplication
如果默认的SpringApplication
不是你的菜,你可以创建一个本地实例并对其设置。例如,关闭banner:
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(Application20200106.class);
springApplication.setBannerMode(Banner.Mode.OFF);
springApplication.run(args);
}
传给SpringApplication
的构造方法参数是Spring beans的配置源。在大多数情况下,都是引用@Configuration
类,但是也可以引用XML配置或引用被扫描的包。
引用XML配置:
ResourceLoader resourceLoader = new ClassPathXmlApplicationContext("config/spring/user/applicationContext-user.xml");
SpringApplication springApplication = new SpringApplication(resourceLoader,Application20200106.class);
引用被扫描的包:
配置类UserConfiguration
:
package cn.shrmus.springboot.demo20200106.configuration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan("cn.shrmus.springboot.demo20200106.user")
@Configuration
public class UserConfiguration {
}
启动类Application20200106
:
@Import(value = cn.shrmus.springboot.demo20200106.configuration.UserConfiguration.class)
@SpringBootApplication
public class Application20200106{
public static void main(String[] args) {
ResourceLoader resourceLoader = new AnnotationConfigApplicationContext("cn.shrmus.springboot.demo20200106.user");
// ResourceLoader resourceLoader = new AnnotationConfigApplicationContext(cn.shrmus.springboot.demo20200106.configuration.UserConfiguration.class);
SpringApplication springApplication = new SpringApplication(resourceLoader,Application20200106.class);
ConfigurableApplicationContext configurableApplicationContext = springApplication.run(args);
UserController userController = configurableApplicationContext.getBean(UserController.class);
System.out.println(userController);
SpringApplication.exit(configurableApplicationContext);
}
也可以使用application.properties
文件配置SpringApplication
,详情参考外部化配置。
要查看SpringApplication
的完整配置,参考SpringApplication
Javadoc。
1.5 构建流式API
如果需要构建一个ApplicationCOntext
层次结构(具有父/子关系的多个上下文),或者你更喜欢使用构建“流式”API,你可以使用SpringApplicationBuilder
。
The
SpringApplicationBuilder
lets you chain together multiple method calls and includesparent
andchild
methods that let you create a hierarchy, as shown in the following example:
使用SpringApplicationBuilder
将包含parent
和child
方法等多个方法的调用都链在一起,以此创建一个层次结构,如下:
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
创建ApplicationContext
层次结构会有一些限制,Web组件被包含在子上下文中,父上下文和子上下文都使用同一个Environment
。阅读SpringApplicationBuilder
Javadoc查看详情。
1.6 Application事件和监听器
除了常见的Spring框架事件(如ContextRefreshedEvent
)外,SpringApplication
还发送一些额外的应用程序事件。
有些事件是在创建ApplicationContext
之前触发的,所以不能将监听器注册成@Bean
,你可以使用SpringApplication.addListeners(…)
方法或SpringApplicationBuilder.listeners(…)
方法注册它们。
如果你希望监听器能自动注册,不管应用程序时如何创建的,你可以在META-INF/spring.factories
文件中使用org.springframework.context.ApplicationListener
添加监听器的引用。如下:
org.springframework.context.ApplicationListener=cn.shrmus.springboot.demo20200106.listener.MyListener
在程序运行时,应用程序事件按一下顺序发送:
ApplicationStartingEvent
在运行开始但还没有任何处理之前发送,监听器和初始化的注册除外。ApplicationEnvironmentPreparedEvent
在Environment
要在已知的上下文中被使用,但上下文创建之前发送。ApplicationContextInitializedEvent
在ApplicationContext
准备好,ApplicationContextInitializers被调用,但还没加载任何bean definitions之前发送。ApplicationPreparedEvent
在bean definitions加载后,启动刷新之前发送。ApplicationStartedEvent
在上下文刷新之后,调用应用程序和命令行运行程序之前发送。ApplicationReadyEvent
在应用程序和命令行运行程序被调用后发送。它表明应用程序已经准备好为请求提供服务。ApplicationFailedEvent
在启动出现异常时发送。
上面的列表只包含绑定到SpringApplication
中的SpringApplicationEvent
。除此之外,以下事件会在ApplicationPreparedEvnet
之后和ApplicationStartedEvent
之前发布:
ContextRefreshedEvent
在刷新ApplicationContext
时发送。
A
WebServerInitializedEvent
is sent after theWebServer
is ready.ServletWebServerInitializedEvent
andReactiveWebServerInitializedEvent
are the servlet and reactive variants respectively.
WebServerInitializedEvent
在WebServer
准备好之后发送。ServletWebServerInitializedEvent
和ReactiveWebServerInitializedEvent
分别作用于servlet和reactive。(原文中variants原意是变种)
通常不需要使用应用程序事件,但是知道它们的存在是很方便的。在内部,Spring Boot使用事件处理各种任务。
Application events are sent by using Spring Framework’s event publishing mechanism. Part of this mechanism ensures that an event published to the listeners in a child context is also published to the listeners in any ancestor contexts. As a result of this, if your application uses a hierarchy of
SpringApplication
instances, a listener may receive multiple instances of the same type of application event.
应用程序事件是使用Spring框架的事件发布机制发送的。此机制的一部分确保将事件发布到子上下文中的监听器,也能将事件发布到任何祖先上下文的监听器。因此,如果你的应用程序使用了SpringApplication
实例的层次结构,则监听器可能会接收同一类型应用程序事件的多个实例。
To allow your listener to distinguish between an event for its context and an event for a descendant context, it should request that its application context is injected and then compare the injected context with the context of the event. The context can be injected by implementing
ApplicationContextAware
or, if the listener is a bean, by using@Autowired
.
允许监听器区分它的上下文事件和子上下文的事件,它应该请求注入它的应用程序上下文,然后将注入的上下文与事件的上下文比较。上下文可以通过ApplicationContextAware
实现注入,或者,如果监听器是bean,可以通过@Autowired
注入。
1.7 Web Environment
一个SpringApplication
会替你创建正确类型的ApplicationContext
。用于确定WebApplicationType
的算法相当简单:
- 如果存在Spring MVC,使用
AnnotationConfigServletWebServerApplicationContext
- 如果不在存Spring MVC,但是存在Spring WebFlux,使用
AnnotationConfigReactiveWebServerApplicationContext
- 否则,使用
AnnotationCon