1. SpringApplication
SpringApplication类提供了一种方便的方法来引导从main()方法启动的Spring应用程序。在许多情况下,您可以委托给静态SpringApplication.run方法,如下面的示例所示
public static void main(String[] args) {
SpringApplication.run(MySpringConfiguration.class, args);
}
当您的应用程序启动时,您应该看到类似于以下输出的内容:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: v2.3.4.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之外的日志级别,可以按照日志级别中描述的那样设置它。应用程序版本是使用主应用程序类s包中的实现版本确定的。启动信息记录可以通过设置spring.main来关闭。log-startup-info为假。这也将关闭应用程序活动配置文件的日志记录。
要在启动期间添加其他日志记录,可以在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提供了许多 FailureAnalyzer实现,您可以 添加自己的实现 。
如果没有故障分析程序能够处理异常,您仍然可以显示完整的条件报告,以更好地理解出错的原因。为此,您需要为org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener启用调试属性或启用调试日志记录。
例如,如果您使用java -jar运行您的应用程序,您可以启用debug属性,如下所示
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
1.2。 懒加载
SpringApplication允许懒加载应用程序。当懒加载被启用时,bean将在需要时创建,而不是在应用程序启动时创建。因此,启用懒加载可以减少应用程序启动所需的时间。在web应用程序中,启用懒加载将导致许多与web相关的bean直到收到HTTP请求后才初始化。
延迟初始化的缺点是,它可能会延迟发现应用程序问题的时间。 如果错误配置的Bean延迟初始化,则启动期间将不再发生故障,并且只有在初始化Bean时问题才会变得明显。 还必须注意确保JVM具有足够的内存来容纳所有应用程序的bean,而不仅仅是启动期间初始化的bean。 由于这些原因,默认情况下不会启用延迟初始化,因此建议在启用延迟初始化之前先对JVM的堆大小进行微调。
可以使用SpringApplicationBuilder上的lazyInitialization方法或SpringApplication上的setLazyInitialization方法以编程方式启用延迟初始化。 另外,可以使用spring.main.lazy-initialization属性启用它,如以下示例所示:
spring.main.lazy-initialization=true
如果希望禁用某些bean的懒加载,同时对应用程序的其余部分使用懒加载,可以使用@Lazy(false)注释显式地将它们的延迟属性设置为false。
1.3。 自定义横幅
可以通过在类路径中添加一个banner.txt文件或设置spring.banner来更改在启动时打印的横幅。属性设置为该文件的位置。如果文件的编码不是UTF-8,您可以设置spring.banner.charset。除了文本文件之外,还可以添加横幅。gif, banner.jpg或banner.png图像文件到您的类路径或设置spring.banner.image。位置属性。图像被转换成ASCII艺术表示,并打印在任何文本横幅上。
在您的banner.txt文件中,您可以使用以下任何占位符
SpringApplication。如果想以编程方式生成横幅,可以使用setBanner()方法。使用org.springframework.boot。Banner接口并实现自己的printBanner()方法。
您还可以使用spring.main.banner-mode属性来确定横幅是否必须在System.out(控制台)上打印,是否必须发送到配置的记录器(日志)或根本不打印(关闭)。
打印的横幅广告使用以下名称注册为单例bean:springBootBanner。
1.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。 有关详细信息,请参见外部化配置。
有关配置选项的完整列表,请参见 SpringApplicationJavadoc 。
1.5。 Fluent Builder API
如果您需要构建 ApplicationContext层次结构(具有父/子关系的多个上下文),或者您更喜欢使用“流利的”构建器API,则可以使用 SpringApplicationBuilder。
SpringApplicationBuilder允许您将多个方法调用链接在一起,并包含父方法和子方法,以便创建层次结构,如下面的示例所示
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
在创建ApplicationContext层次结构时有一些限制。例如,Web组件必须包含在子上下文中,并且父上下文和子上下文使用相同的环境。详细信息请参见SpringApplicationBuilder Javadoc。
1.6。 应用程序可用性
在平台上部署时,应用程序可以使用诸如Kubernetes Probes之类的基础结构向平台提供有关其可用性的信息。 Spring Boot对常用的“活动性”和“就绪性”可用性状态提供了开箱即用的支持。 如果您使用的是Spring Boot的“执行器”支持,则这些状态将显示为运行状况端点组。
此外,您还可以通过将ApplicationAvailability接口注入您自己的bean来获得可用性状态。
1.6.1。 生命状态
应用程序的“活动”状态表明其内部状态是否允许其正常运行,或者在当前出现故障时自行恢复。 损坏的“活动”状态意味着应用程序处于无法恢复的状态,并且基础结构应重新启动应用程序。
通常,“活动”状态不应基于外部检查(例如健康检查)。 如果确实如此,则发生故障的外部系统(数据库,Web API,外部缓存)将触发整个平台的大量重启和级联故障。
Spring引导应用程序的内部状态主要由Spring ApplicationContext表示。如果应用程序上下文已经成功启动,Spring Boot将假定应用程序处于有效状态。一旦上下文被刷新,应用程序就被认为是活动的,请参阅Spring Boot应用程序生命周期和相关应用程序事件。
1.6.2。就绪状态
应用程序的“就绪”状态告诉应用程序是否已准备好处理流量。 失败的“就绪”状态告诉平台当前不应将流量路由到应用程序。 这通常发生在启动过程中,正在处理CommandLineRunner和ApplicationRunner组件时,或者在应用程序认为它太忙以至于无法获得额外流量的任何时候。
一旦调用了应用程序和命令行运行程序,就认为该应用程序已准备就绪,请参阅Spring Boot应用程序生命周期和相关的Application Events。
期望在启动期间运行的任务应该由CommandLineRunner和ApplicationRunner组件执行,而不是使用Spring组件生命周期回调,如@PostConstruct。
1.6.3。 管理应用程序可用性状态
通过注入ApplicationAvailability接口并在其上调用方法,应用程序组件可以在任何时候检索当前的可用性状态。更常见的情况是,应用程序希望侦听状态更新或更新应用程序的状态。
例如,我们可以将应用程序的“准备就绪”状态导出到一个文件中,以便Kubernetes的“exec探针”可以查看该文件
@Component
public class ReadinessStateExporter {
@EventListener
public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {
switch (event.getState()) {
case ACCEPTING_TRAFFIC:
// create file /tmp/healthy
break;
case REFUSING_TRAFFIC:
// remove file /tmp/healthy
break;
}
}
}
当应用程序崩溃且无法恢复时,我们还可以更新应用程序的状态:
@Component
public class LocalCacheVerifier {
private final ApplicationEventPublisher eventPublisher;
public LocalCacheVerifier(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void checkLocalCache() {
try {
//...
}
catch (CacheCompletelyBrokenException ex) {
AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN);
}
}
}
Spring Boot为执行器运行状况端点的“活动”和“准备就绪”提供了Kubernetes HTTP探针。在专门的部分中,您可以获得关于在Kubernetes上部署Spring引导应用程序的更多指导。
1.7。 应用程序事件和监听器
除了通常的Spring框架事件(如ContextRefreshedEvent)之外,spring应用程序还会发送一些附加的应用程序事件。
实际上在创建ApplicationContext之前会触发一些事件,因此您不能将这些事件注册为@Bean。 您可以使用SpringApplication.addListeners(…)方法或SpringApplicationBuilder.listeners(…)方法注册它们。
如果希望这些侦听器自动注册,而不管创建应用程序的方式如何,都可以将META-INF / spring.factories文件添加到项目中,并使用org.springframework.context引用您的侦听器。 ApplicationListener键,如以下示例所示:
org.springframework.context.ApplicationListener = com.example.project.MyListener
应用程序事件在您的应用程序运行时按以下顺序发送:
-
ApplicationStartingEvent在运行开始时但在任何处理之前发送,listeners 和initializers的注册除外。
-
ApplicationEnvironmentPreparedEvent在context的Environment准备好之后但在创建上下文之前发送。
-
ApplicationContextInitializedEvent 在ApplicationContext准备后同时ApplicationContextInitializers被调用但在任何bean definition被加载之前
-
An ApplicationPreparedEvent is sent just before the refresh is started but after bean definitions have been loaded.
-
ApplicationPreparedEvent是在refresh启动之前但加载bean定义之后发送的。
-
AvailabilityChangeEvent 紧随其后用LivenessState.CORRECT 指示应用程序是活动的
-
ApplicationReadyEvent在调用任何应用程序和命令行运行程序之后将发送。
-
AvailabilityChangeEvent紧随其后发送ReadabilityState.ACCEPTING_TRAFFIC以指示应用程序已准备就绪,可以处理请求。
-
ApplicationFailedEvent将会在启动时出现异常时发送。
上面的列表只包含绑定到SpringApplication的SpringApplicationEvents。除此之外,还会在ApplicationPreparedEvent之后和ApplicationStartedEvent之前发布以下事件
- WebServerInitializedEvent将会在WebServer 准备好之后发送. ServletWebServerInitializedEvent 和ReactiveWebServerInitializedEvent 分别是servlet和反应式变量.
A。 ContextRefreshedEvent发送 ApplicationContext刷新后
您通常不需要使用应用程序事件,但是知道它们的存在是很方便的。在内部,Spring Boot使用事件来处理各种任务。
默认情况下,事件侦听器不应该运行可能很长时间的任务,因为它们在同一线程中执行。考虑使用应用程序和命令行运行器。
应用程序事件是通过Spring Framework的事件发布机制发送的。这种机制的一部分可以确保发布到子上下文中侦听器的事件也会发布到任何祖先上下文中的侦听器。因此,如果应用程序使用SpringApplication实例的层次结构,侦听器可能会接收到相同类型的应用程序事件的多个实例。
为了使您的侦听器能够区分其上下文的事件和后代上下文的事件,它应请求注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。 可以通过实现ApplicationContextAware来注入上下文,或者,如果侦听器是bean,则可以使用@Autowired注入上下文。
1.8。 网络环境
SpringApplication尝试代表您去创建正确类型的ApplicationContext。用于确定WebApplicationType的算法如下所示
-
如果存在Spring MVC,则使用一个AnnotationConfigServletWebServerApplicationContext
-
如果Spring MVC不存在,而Spring WebFlux存在,那么就使用注释configreactivewebserverapplicationcontext
-
否则,使用AnnotationConfigApplicationContext
这意味着如果您在同一个应用程序中使用Spring MVC和来自Spring WebFlux的新WebClient, Spring MVC将被默认使用。您可以通过调用setWebApplicationType(WebApplicationType)轻松地覆盖它。
也可以完全控制调用setApplicationContextClass()所使用的ApplicationContext类型。
当在JUnit测试中使用SpringApplication时,通常需要调用setWebApplicationType(WebApplicationType.NONE)。
1.9。 访问应用程序参数
如果您需要访问传递给SpringApplication.run()的应用程序参数,您可以注入org.springframework.boot。ApplicationArguments bean。ApplicationArguments接口提供对原始字符串[]参数以及解析的选项和非选项参数的访问,如下面的示例所示
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引导还向Spring环境注册了一个CommandLinePropertySource。这还允许您通过使用@Value注释注入单个应用程序参数。
1.10。 使用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 Bean,则可以另外实现org.springframework.core.Ordered接口或使用org.springframework.core.annotation.Order注释。
1.11。 Application 退出
每个都 SpringApplication向JVM注册一个关闭钩子,以确保 ApplicationContext退出时正常关闭。 可以使用所有标准的Spring生命周期回调(例如 DisposableBean接口或 @PreDestroy批注)。
此外,bean可以实现org.springframework.boot。如果它们希望在调用SpringApplication.exit()时返回特定的退出代码,则调用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接口也可以通过异常实现。当遇到这样的异常时,Spring Boot将返回由已实现的getExitCode()方法提供的退出代码。
1.12。 管理员功能
Spring Boot允许您具体化您的配置,以便您可以在不同的环境中使用相同的应用程序代码。您可以使用属性文件、YAML文件、环境变量和命令行参数来具体化配置。属性值可以通过使用@Value注释直接注入到bean中,也可以通过Spring环境抽象访问,或者通过@ConfigurationProperties绑定到结构化对象。
如果您想知道应用程序在哪个HTTP端口上运行,请通过键获取属性 local.server.port。