Springboot核心特性--SpringApplication

本文详细介绍了如何通过SpringApplication启动Spring应用程序,包括启动日志、配置级别、启动失败分析、懒初始化、自定义Banner、ApplicationRunner和CommandLineRunner的使用,以及Web环境和应用参数的访问。
摘要由CSDN通过智能技术生成

通过SpringApplication类,你可以从main()方法中启动Spring应用程序。在许多情况下,你可以直接调用SpringApplication.run静态方法,如下例子

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

当你程序启动时可以看到类似以下的日志输出:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::       (v3.2.0-SNAPSHOT)

2023-09-10T13:33:54.881+08:00  INFO 14060 --- [           main] o.s.b.d.f.s.MyApplication                : Starting MyApplication using Java 17 with PID 14060 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
2023-09-10T13:33:54.887+08:00  INFO 14060 --- [           main] o.s.b.d.f.s.MyApplication                : No active profile set, falling back to 1 default profile: "default"
2023-09-10T13:33:56.187+08:00  INFO 14060 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2023-09-10T13:33:56.202+08:00  INFO 14060 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-09-10T13:33:56.202+08:00  INFO 14060 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.10]
2023-09-10T13:33:56.344+08:00  INFO 14060 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-09-10T13:33:56.347+08:00  INFO 14060 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1389 ms
2023-09-10T13:33:56.821+08:00  INFO 14060 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-09-10T13:33:56.831+08:00  INFO 14060 --- [           main] o.s.b.d.f.s.MyApplication                : Started MyApplication in 2.379 seconds (process running for 2.715)

 默认情况下,会显示INFO级别的日志信息,包括一些相关的启动细节,比如启动应用程序的用户。如果你需要INFO以外级别的日志,你可以设置它,如下面日志级别的配置,应用程序的版本时使用main方法所在类的包的实现版本来确定的。启动信息的 记录可以通过设置spring.main.log-startup-info为false来关闭。这也将光比应用程序的激活的profiles的日志记录。

logging:
  level:
    root: "warn"
    org.springframework.web: "debug"
    org.hibernate: "error"

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 is listening on port 8080 or configure this application to listen on another port.

✦  SpringBoot提供了许多FailureAnalyzer的实现,你也可以添加自己的实现。这里就不多说了。

如果failure analyzer不能够处理异常,你仍然可以显示完整的条件报告以更好地了解出错的原因。要实现这个,你需要为org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener启用debug属性或启用DEBUG日志。

例如,如果你通过使用java -jar 来运行你的应用程序,你可以按以下方式启用debug属性。

$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug

1.2 懒初始化(Lazy Initialization)

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)注解将器lazy属性显示地设置为false。

1.3 自定义Banner 

启动时打印的Banner可以通过在classpath中添加banner.txt文件或通过spring.banner.location属性设置为该文件的位置来自定义。如果该文件的编码不是UTF-8,你可以通过spring.banner.charset属性设置其字符编码。

在你的banner.txt文件中,你可以使用Enviroment中任何key,以及以下任何占位符。

变量介绍

${application.version}

你的应用程序的版本号,也就是 MANIFEST.MF 中声明的。 例如,Implementation-Version: 1.0 被打印为 1.0

${application.formatted-version}

你的应用程序的版本号,如在`MANIFEST.MF`中声明的那样,并以格式化显示(用括号包围,以 v 为前缀)。 例如 (v1.0)

${spring-boot.version}

你所使用的Spring Boot版本。 例如 3.2.0-SNAPSHOT 。

${spring-boot.formatted-version}

你正在使用的Spring Boot版本,格式化显示(用大括号包围并以 v 为前缀)。 例如 (v3.2.0-SNAPSHOT)

${Ansi.NAME} (或 ${AnsiColor.NAME}${AnsiBackground.NAME}${AnsiStyle.NAME})

其中 NAME 是一个ANSI转义代码的名称。 详见 AnsiPropertySource 。

${application.title}

你的应用程序的标题,正如在 MANIFEST.MF 中声明的那样。 例如, Implementation-Title: MyApp 被打印成 MyApp

✦ 如果你想以编程方式生成一个Banner,可以使用SpringApplication.setBanner()方法。实现org.springframework.boot.Banner接口并实现自己的printBanner()方法。

你也可以使用spring.main.banner-mode属性来决定Beann打印模式。例如打印到System.out(console)上,发送到配置的logger。打印的Banner被注册为一个单例Bean,名字是springBootBanner。

 ✦ ${application.version}和${application.formatted-version}属性只有在你使用Springboot启动器时才可用。如果你正在运行一个未打包的jar,并使用java -cp <classpath> <mianclass>启动它,这些值将不会被解析。 这就是为什么我们建议总是使用【java org.springframework.boot.loader.JarLauncher】来启动未打包的jar。这将在构建classpath和启动你的应用程序之前初始化application.*的Banner变量。

1.4 自定义SpringApplication

如果SpringApplication的默认值不符合你的需求,你可以创建一个实例并对其进行自定义。例如要关闭Banner,你可以这样写。

import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(MyApplication.class);
        application.setBannerMode(Banner.Mode.OFF);
        application.run(args);
    }
}

1.5 Builder API 

如果你需要建立一个包含层次结构的ApplicationContext(具有父/子关系多个context),或者你喜欢使用‘fluent’Builder API,你可以使用SpringApplicationBuilder。

SpringApplicationBuilder允许你链式调用多个方法,包括调用parent和child方法,创建一个层次结构,如下所示。

new SpringApplicationBuilder().sources(Parent.class)
    .child(Application.class)
    .bannerMode(Banner.Mode.OFF)
    .run(args);

1.6 Application事件和监听器

除了常见的Spring框架,如ContextRefresheEvent外,SpringApplication还会发布一些额外的应用事件。

有些事件实际上是在ApplicationContext被创建之前触发的,所以你不能以@Bean的形式注册一个监听器。你可以通过SpringApplication.addListeners()方法或者SpringApplicationBuilder.listeners()方法注册它们。

如果你想让这些监听器自动注册,不管应用程序是如何创建的,你可以在你的项目添加一个META-INF/spring.factories文件,并通过ora.springframework.context.ApplicationListener属性来配置你的监听器,如下所示。

org.springframework.context.ApplicationListener=com.example.project.MyListener

 当应用程序运行时,Application event按以下顺序发布:

  1. 一个ApplicationStartingEvent在运行开始时被发布,但在任何处理之前,除了注册监听器和初始化器之外。
  2. 当在上下文中使用Enviroment已知,但在创建上下文之前,将发布ApplicationEnvironmentPreparedEvent。
  3. 当ApplicationContext已准备好并且ApplicationContextInitializers被调用,但在任何Bean定义被加载之前ApplicationContextInitializedEvent被发布。
  4. 一个ApplicationprepareEvent将在刷新开始之前但在Bean定义加载后被发布。
  5. 在上下文被刷新之后,但在任何应用程序和命令行运行程序被调用之前,将发布一个ApplicationStartedEvent。
  6. 紧着这发布LivenessState.CORRECT状态的AvailabilityChangeEvent,表明应用程序被认为是存活的
  7. 在任何ApplicationRunner和CommandLineRunner被调用后,将发布一个ApplicationReadEvent
  8. 紧接着发布ReadinessState.ACCEPING_TRAFFIC状态的AvailabilityChangeEvent,表明应用程序已经准备好为请求提供服务。
  9. 如果启动时出现异常,将发布一个ApplicationFaildEvent。

以上列表仅包含与SpringApplication相关的SpringApplicationEvent。除此以外,以下事件也会在ApplicationPreparedEvent之后和ApplicationStartedEvent之前发布。

  •  在WebServer准备好发布WebServerIniteializedEvent。ServletWebServerInitializedEvent和ReactiveWebServerInitializedEvent分布对应Servlet和reactive的实现。
  • 当ApplicationContext被刷新时,将发布一个ContextRefreshedEvent。

✦ 你通常不需要使用application event,但直到它们的存在会很方便。在内部,Springboot使用事件来处理各种任务。 

1.7 WEB环境(Environment) 

SpringApplication会视图帮你创建正确类型的ApplicationContext。确定为WebApplicationType的算法如下。

  • 如果Spring MVC存在,就会使用AnnotationConfigServletWebServerApplicationContext。
  • 如果Spring MVC不存在而Spring WebFlux存在,则使用AnnotationConfigReactiveWebServerApplicationContext。
  • 否则,将使用AnnotationConfigApplicationContext。

 这意味着,如果你再同一个应用程序中使用Spring MVC和新的WebClient(来自于Spring WebFlux),Spring MVC将被默认使用。你可以通过调用setWebApplicationType(WebApplicationType)来轻松覆盖。

也可以通过调用 setApplicationContextFactory()来完全控制使用的ApplicationContext类型。

1.8 访问应用参数

如果你需要访问传递给SpringApplication.run()的命令行参数,你可以注入一个org.springframework.boot.ApplicationArguments bean。通过ApplicationArguments接口,你可以访问原始的String[]参数以及经过解析的option和non-option参数。如下所示:

import java.util.List;

import org.springframework.boot.ApplicationArguments;
import org.springframework.stereotype.Component;

@Component
public class MyBean {
    public MyBean(ApplicationArguments args) {
        boolean debug = args.containsOption("debug");
        List<String> files = args.getNonOptionArgs();
        if (debug) {
            System.out.println(files);
        }
        // if run with "--debug logfile.txt" prints ["logfile.txt"]
    }
}

1.9 使用ApplicationRunner或CommandLineRunner 

如果你需要在SpringApplication启动后运行一些特定的代码,你可以实现ApplicationRunner或者CommandLineRunner接口。这两个接口以相同的方式工作,并提供一个单一的run方法,该方法在SpringApplication.run()执行完毕之前被调用。

★  这很适合我们用于执行那些需要在处理HTTP请求之前的任务。

CommandLineRunner接口以字符串数组形式提供了对应用程序参数的访问。而ApplicationRunner使用前面讨论的ApplicationArguments接口。下面是显示了一个带有run方法的CommandLineRunnerd的例子:

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) {
        // Do something...
    }
}

如果定义了多个CommandLineRunner或ApplicationRunner  Bean,并且需要他们按照特定的顺序先后执行。那么可以实现org.springframework.core.Ordered接口 或使用org.springframework.core.annotation.Order注解来指定顺序。 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

钟小猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值