一、SpringApplication
SpringApplication
类提供了一种方便的方法来引导从main()方法启动的Spring应用程序。在许多情况下,您可以委托给SpringApplication.run
静态方法,如下面的示例所示
public static void main(String[] args) {
SpringApplication.run(MySpringConfiguration.class, args);
}
当您的应用程序启动时,您应该会看到类似以下输出的内容
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _
( ( )\___ | '_ | '_| | '_ / _` |
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: v2.2.6.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、启动失败
如果您的应用程序启动失败,注册的故障分析器FailureAnalyzers
将会提供对应的错误信息和解决问题的具体操作。
例如,如果您在端口8080上启动一个web应用程序,并且该端口已经在使用,那么您应该看到类似以下消息的内容:
***************************
APPLICATION FAILED TO START
***************************
Description:
Embedded servlet container failed to start. Port 8080 was already in use.
Action:
确定并停止正在端口8080上侦听的进程,或将此应用程序配置为在另一个端口上侦听。
Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.
Spring Boot提供了大量的FailureAnalyzer
实现,我们也可以添加自己的实现。
如果没有FailureAnalyzer
能够处理该异常,您仍然可以显示完整情况报告,以更好地了解出了什么问题。 为此,您需要为org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
启用debug
属性或启用DEBUG
日志记录。
例如,如果您使用java -jar运行您的应用程序,您可以启用debug属性,如下所示:
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
2、懒初始化
SpringApplication
允许懒初始化应用程序。 启用懒初始化后,不会在应用程序启动期间创建bean,而是在收到请求后要使用对应的bean时才会创建相应的bean。这样可以减少应用程序启动的时间。
延迟初始化的缺点是,它可能会导致你不能立即发现一些错误。如果配置错误的bean被懒加载,则在启动期间将不会报错,只有在初始化这个Bean时才会出现问题。 还必须注意确保JVM具有足够的内存容纳启动时初始化的bean和延迟加载的bean。
因此,默认情况下不会启用懒初始化,因此建议在启用懒初始化之前先对JVM的堆大小进行调整。
配置懒初始化
spring.main.lazy-initialization=true
如果你希望应用程序懒初始化,但是对其中一些bean又不希望它懒初始化,那么可以使用@Lazy(false)注释显式地将它们的懒加载属性设置为false。
3、自定义横幅
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _
( ( )\___ | '_ | '_| | '_ / _` |
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: v2.2.6.RELEASE
启动时打印的图案
可以通过将banner.txt
文件添加到您的类路径或通过将spring.banner.location
属性设置为此类文件的位置来更改启动时打印的横幅。
如果文件的编码不是UTF-8,则可以设置spring.banner.charset
。 除了文本文件之外,您还可以将banner.gif
,banner.jpg
或banner.png
图像文件添加到类路径中,或设置spring.banner.image.location
属性。 图像将转换为ASCII的形式并打印在任何文本横幅上方。
横幅中可以使用的变量:
Variable | Description |
---|---|
${application.version} |
MANIFEST.MF 中声明应用程序的版本号。例如Implementation-Version: 1.0 则会被打印1.0 |
${application.formatted-version} |
MANIFEST.MF 中声明应用程序的版本号并格式化显示(用括号包围并在版本号前加个v。(v1.0) ) |
${spring-boot.version} |
使用的springBoot的版本号. 例如2.2.6.RELEASE . |
${spring-boot.formatted-version} |
使用的springBoot的版本号并格式化显示。例如(v2.2.6.RELEASE) . |
${Ansi.NAME} (or ${AnsiColor.NAME} , ${AnsiBackground.NAME} , ${AnsiStyle.NAME} ) |
其中NAME 是ANSI转义码。 有关详细信息,请参见AnsiPropertySource 。 |
${application.title} |
在MANIFEST.MF中声明的应用程序的标题。例如, Implementation-Title: MyApp 被打印成 MyApp . |
如果要以编程方式生成横幅,可以使用SpringApplication.setBanner(…)
方法。 使用org.springframework.boot.Banner
接口并实现自己的printBanner()
方法。
您还可以使用spring.main.banner-mode
属性来控制横幅是否在控制台上打印,是否要打印到日志。
打印出来的banner被注册为一个单例bean,名字如下:springBootBanner
。
4、自定义SpringApplication
如果不想使用SpringApplication
的默认设置,那么你可以自定义一个实例。例如,要关掉横幅,你可以写
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
传递给SpringApplication
的构造器参数是spring bean的配置源。在大多数情况下,这些是对@Configuration注解的类,但是它们也可以是对XML配置或应该扫描的包。
也可以通过使用application.properties
文件配置SpringApplication
。 有关详细信息,请参见外部化配置(Externalized Configuration)。
有关配置选项的完整列表,请参见SpringApplication
Javadoc
5、Fluent Builder API快速构建API
如果您需要构建ApplicationContext
层次结构(具有父/子关系的多个上下文),或者如果您更喜欢使用快速构建器API,则可以使用SpringApplicationBuilder
。也就是调用方法后仍返回本对象,与StringBuilder
相似
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
创建ApplicationContext
层次结构时存在一些限制。例如,Web组件必须包含在子上下文中,并且父上下文和子上下文都使用相同的环境。有关详细信息,请参阅SpringApplicationBuilder
Javadoc 。
6、应用事件和监听器
除了通常的Spring Framework事件(例如ContextRefreshedEvent
)之外,SpringApplication
还发送了其他应用事件。
一些事件通常在ApplicationContext
创建之前就被触发,所以你不可能使用@Bean注册一个监听器来监听这些事件。但是你可以通过SpringApplication.addListeners(...)
方法或者SpringApplicationBuilder.listeners(...)
方法来注册。
如果你希望这些监听器在程序启动时被自动注册,你可以添加META-INF/spring.factories
文件到你的项目中,并在文件中使用org.springframework.context.ApplicationListener
来引用监听器,如下
org.springframework.context.ApplicationListener=com.example.project.MyListener
在你的应用程序运行时,将按一下顺序发送事件
ApplicationStartingEvent
:在应用程序开始运行,但未进行任何处理时(此时侦听器和初始化程序的注册已完成)发送。ApplicationEnvironmentPreparedEvent
:在准备好上下文环境Environment
,但是上下文context也就是ioc容器还未创建好之前发送ApplicationContextInitializedEvent
:在ApplicationContext
准备好并且ApplicationContextInitializers
回调完成,但是还没有bean被加载时发送ApplicationPreparedEvent
:在容器刷新之前,但是bean加载之后发送ApplicationStartedEvent
:在容器刷新之后,但在调用应用程序和命令行runner方法之前ApplicationReadyEvent
:在调用runner方法之后,说明应用已经准备好接受请求ApplicationFailedEvent
:启动发生异常时发送
上面的列表仅包含绑定到SpringApplication
的SpringApplicationEvents
。 除这些以外,下面的事件也在ApplicationPreparedEvent
之后和ApplicationStartedEvent
之前发布:
ContextRefreshedEvent
:在ApplicaitonContext
刷新是启动WebServerInitializdEvent
:在WebServer
就绪后发送。ServletWebServerInitializedEvent
和ReactiveWebServerInitializedEvent
分别是servlet和reactive变体。
您通常不会使用应用程序事件,但是知道它们的存在是很有好处的。在Spring Boot内部使用事件来处理各种任务。
应用程序事件是通过使用Spring Framework的事件发布机制发送的。 此机制的确保了在子级上下文中发布给监听器的事件在其任何祖先上下文中也会发布给监听器。
这样的结果就是,如果您的应用程序使用SpringApplication
实例的层次结构,则监听器可能会收到同一类型的应用事件的多个实例。
为了使您的监听器能够区分其上下文事件和其后代上下文的事件,应该要求注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。 可以监听器可以通过实现ApplicationContextAware
来注入上下文,或者,如果监听器是bean,则可以使用@Autowired
注入上下文。
7、Web环境
SpringApplication
代替你创建正确类型的ApplicationContext
。用于确定WebApplicationType
的算法相当简单。
- 如果存在Spring MVC,则
AnnotationConfigServletWebServerApplicationContext
被使用 - 如果不存在Spring MVC,则
AnnotationConfigReactiveWebServerApplicationContext
被使用 - 否则,
AnnotationConfigApplicationContext
被使用
这意味着,如果你在一个应用程序中同时使用Spring MVC和来自Spring WebFlux的新WebClient
,那么默认情况下将使用Spring MVC。您可以通过调用setWebApplicationType(WebApplicationType)
来轻松地复写它。
还可以通过调用setApplicationContextClass()
来控制ApplicationContext
类型。
在JUnit测试中使用SpringApplication
时,通常需要调用setWebApplicationType(WebApplicationType.NONE)
。
8、访问应用参数
如果您需要访问传递给SpringApplication.run(...)
的应用程序参数,则可以注入org.springframework.boot.ApplicationArguments
bean。 ApplicationArguments
接口提供对原始String []参数以及已解析的选项和非选项参数的访问,如以下示例所示:
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注解注入单个应用程序参数。
9、使用ApplicationRunner和CommandLineRunner
如果在SpringApplication
启动后需要运行某些特定的代码,则可以实现ApplicationRunner
或CommandLineRunner
接口。 两个接口都以相同的方式工作并提供一个run
方法,该方法在SpringApplication.run(...)
完成之前被调用。
CommandLineRunner
接口以简单的字符串数组提供对应用程序参数的访问,而ApplicationRunner
使用前面讨论的ApplicationArguments
接口。 以下示例显示了带有run方法的CommandLineRunner
:
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注册一个关闭钩子,以确保ApplicationContext
在退出时正常关闭。 可以使用所有标准的Spring生命周期回调(例如DisposableBean
接口或@PreDestroy
注解)。
另外,如果bean希望在调用SpringApplication.exit()
时返回特定的退出代码,则可以实现org.springframework.boot.ExitCodeGenerator
接口。 然后可以将此退出代码传递给System.exit()
,以将其作为状态代码返回,如以下示例所示:
@SpringBootApplication
public class ExitCodeApplication {
@Bean
public ExitCodeGenerator exitCodeGenerator() {
return () -> 42;//lambda表达式
//相当于
/*
*return new ExitCodeGenerator() {
* @Override
* public int getExitCode() {
* return 15;
* }
*};
*/
}
public static void main(String[] args) {
System.exit(SpringApplication.exit(SpringApplication.run(ExitCodeApplication.class, args)));
}
}
另外,ExitCodeGenerator
接口可以通过异常实现。 遇到此类异常时,Spring Boot返回实现的getExitCode()
方法提供的退出代码。
11、管理功能
通过指定spring.application.admin.enabled
属性,可以为应用程序开启与管理相关的功能。 这将在MBeanServer
平台上公开SpringApplicationAdminMXBean
。 你可以使用此功能来远程管理Spring Boot应用程序。
如果您想知道应用程序在哪个HTTP端口上运行,请使用local.server.port
的键获取属性。