`

Spring Boot(05)——SpringApplication介绍

阅读更多

SpringApplication介绍

通常启动Spring Boot应用时调用SpringApplication类的static run()进行启动。

@SpringBootApplication
public class Application {

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

}

其内部最终会转换为new一个SpringApplication对象,然后调用该对象的run方法,然后整个核心启动逻辑就由SpringApplication对象的run方法完成。

public static ConfigurableApplicationContext run(Class<?>[] primarySources,
        String[] args) {
    return new SpringApplication(primarySources).run(args);
}

调用SpringApplication的静态run方法时,由于SpringApplication对象是在内部创建的,其会在启动Spring Boot时使用一些默认的配置。如果我们需要进行一些自定义配置,则可以自己手动的new一个SpringApplication对象,进行一些特殊配置后再调用SpringApplication对象的实例run方法。比如Spring Boot默认在启动的时候会输出Spring Boot的banner,其中包含了Spring Boot的版本信息,如果我们不希望输出该banner信息,则可以进行如下定制。

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Application.class);
        app.setBannerMode(Banner.Mode.OFF);
        app.run(args);
    }

}

ApplicationEvent及其监听

SpringApplication在启动Spring Boot的过程中会发布以下ApplicationEvent,也可以参考SpringApplication的实例run方法的实现。

  • ApplicationStartingEvent :会在进行其它操作之前发布
  • ApplicationEnvironmentPreparedEvent : 接着是准备Environment,准备好了会发布该事件
  • ApplicationPreparedEvent :接着会构造ApplicationContext,在构造好ApplicationContext之后,调用其refresh()方法之前会发布该事件
  • ApplicationStartedEvent :在ApplicationContext进行refresh之后,调用ApplicationRunner和CommandLineRunner之前会发布该事件
  • ApplicationReadyEvent :在Spring Boot应用启动完成之后,也就是在SpringApplication的run()调用马上结束之前会发布该事件
  • ApplicationFailedEvent :在启动过程中出现异常时会发布该事件

从上述的事件发布过程可以看出,有些事件的发布是在ApplicationContext还没有准备好的情况下发布的,所以它们不能通过传统的定义ApplicationEvent实现类为bean容器中的一个bean的方式进行监听。SpringApplication接口为我们提供了专门的注册这些监听器的方法addListeners()。事件监听器需要实现org.springframework.context.ApplicationListener接口。以下定义了两个事件监听器,都只是简单的进行日志输出,然后在启动应用的时候通过addListeners()添加了监听器,程序启动后会看到这两个监听器输出的日志信息。

@Slf4j
public class ApplicationStartingEventListener implements ApplicationListener<ApplicationStartingEvent> {

    @Override
    public void onApplicationEvent(ApplicationStartingEvent event) {
        log.info("收到Spring Boot应用准备启动的事件[{}]", event);
    }

}

@Slf4j
public class ApplicationReadyEventListener implements ApplicationListener<ApplicationReadyEvent> {

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        log.info("收到Spring Boot应用启动完成的事件[{}]", event);
    }

}

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Application.class);
        app.addListeners(new ApplicationStartingEventListener(), new ApplicationReadyEventListener());
        app.run(args);
    }

}

特别需要注意的是在添加监听器的时候不要调用SpringApplication的setListeners(),而要调用其addListeners()。因为在构造SpringApplication对象的时候构造方法中已经通过Spring Boot的spring factory机制获取并注册了一些ApplicationListener(可以通过调用SpringApplication的getListeners()获取到已经注册的ApplicationListener),使用setListeners()会覆盖掉已经注册过的ApplicationListener。Spring Boot的spring factory机制是指可以创建一个META-INF/spring.factories文件,然后以接口类的全路径名称作为Key,以实现类的全路径名称作为Value,当有多个Value时以英文逗号分隔,当有多个Key时每个Key一行。它们会被SpringFactoriesLoader进行处理,可以通过它获取到定义的接口对应的实现类。Spring Boot中有很多扩展都是基于这个机制进行的。上面的定义的ApplicationListener实现类,如果需要使用spring factory机制,则可以在spring.factories文件中添加如下内容:

org.springframework.context.ApplicationListener=com.elim.springboot.listener.ApplicationStartingEventListener,com.elim.springboot.listener.ApplicationReadyEventListener

当你觉得一行展示的内容太长了,期望折行展示时,可以在行末加上\,这语法跟定义properties文件是一样的。实际上其内部也是按照properties文件进行解析的。

org.springframework.context.ApplicationListener=com.elim.springboot.listener.ApplicationStartingEventListener,\
com.elim.springboot.listener.ApplicationReadyEventListener

通过spring.factories文件定义了ApplicationListener后,我们的启动应用代码就可以改写为如下这种最简单的方式了。

@SpringBootApplication
public class Application {

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

}

ApplicationContext的选择

默认情况下,当ClassPath下存在SpringMVC相关的Class时将使用org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext,当不存在SpringMVC相关的Class,而是存在SpringWebFlux相关的Class时将使用org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext,当两者都不存在时可以使用默认的org.springframework.context.annotation.AnnotationConfigApplicationContext。可以通过其setWebApplicationType(WebApplicationType webApplicationType)手动指定WebApplicationType,从而影响使用的ApplicationContext的选择,也可以直接通过setApplicationContextClass(Class<? extends ConfigurableApplicationContext> applicationContextClass)指定需要使用的ApplicationContext对应的Class。

访问命令行参数

调用SpringApplication的run()时传递的参数通常来自于命令行的参数,SpringApplication内部在调用run()时会把它们封装为一个ApplicationArguments对象,并且会把它定义为bean容器中的一个bean。如果在应用中需要访问命令行传递的参数,则可以通过注入ApplicationArguments对象,进行获取到对应的参数。命令行指定参数时有两种参数,一种是可选型参数、一种是非可选型参数,可选型参数以--开头,需要赋值时可以加上=,比如指定命令行参数为--debug --foo=bar abc,则可选型参数为debug和foo,而非可选型参数为abc。如下代码就是基于该命令行参数的一个简单示例。

@Controller
public class SampleController {

    @Autowired
    private ApplicationArguments arguments;
    
    /**
     * 传递的命令行参数是--debug --foo=bar abc
     * @param writer
     * @throws Exception
     */
    @GetMapping("sample/args")
    public void arguments(PrintWriter writer) throws Exception {
        writer.println("包含debug参数:" + arguments.containsOption("debug"));//true
        writer.println("参数foo的值是:" + arguments.getOptionValues("foo"));//[bar]
        writer.println("其它非选项性参数:" + arguments.getNonOptionArgs());//[abc]
        writer.println("原始参数是:" + Arrays.toString(arguments.getSourceArgs()));//--debug, --foo=bar, abc
    }

}

这种参数有别于在运行程序时通过-Dkey=value指定的虚拟机参数,通过-Dkey=value指定的虚拟机参数可以通过System.getProperty("key")获取到。命令行参数是对应程序运行主命令之后添加的参数,比如上面添加的那些参数的完整指令是java -jar app.jar --debug --foo=bar abc

ApplicationRunner和CommandLineRunner

前面在介绍事件监听器的时候已经介绍了,在Spring Boot应用启动成功后会在bean容器中寻找ApplicationRunner和CommandLineRunner类型的bean,调用它们的run()。所以如果想在Spring Boot应用启动成功或做一些事情,则可以实现自己的ApplicationRunner或CommandLineRunner。它们的区别在于ApplicationRunner的run()的入参是ApplicationArguments对象,而CommandLineRunner的run()的入参是原始的参数数组。

@Component
@Slf4j
public class MyApplicationRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("Spring Boot应用启动成功,携带的命令行参数是:{}", Arrays.toString(args.getSourceArgs()));
    }

}

@Component
@Slf4j
public class MyCommandLineRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        log.info("Spring Boot应用已经启动成功了,携带的命令行参数是:{}", Arrays.toString(args));
    }

}

其实前面介绍事件监听器的时候也提到了,通过实现ApplicationListener,监听ApplicationStartedEvent或ApplicationReadyEvent也可以在Spring Boot应用启动成功后做一些事情。它们的区别主要就在于ApplicationRunner和CommandLineRunner实现类是bean容器中的一个bean,可以注入其它bean,而且它们可以很方便的访问到命令行参数。

SpringApplicationBuilder

在构建SpringApplication对象时也可以通过SpringApplicationBuilder进行构建,通过它可以流式的进行配置,还可以指定子ApplicationContext。

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        // SpringApplication.run(SpringBootApplication.class, args);
        SpringApplication app = new SpringApplicationBuilder(Application.class)
            .child(ChildConfig.class)
            .bannerMode(Banner.Mode.OFF)
            .build();
        app.run(args);
    }

}

关于SpringApplication的更多可定制的信息可以参考对应的API文档。

启用JMX管理

在application.properties文件中添加spring.application.admin.enabled=true可以启用JMX管理,这会发布一个SpringApplicationAdminMXBean类型的MBean。通过它的getProperty()可以获取当前应用对应的启动JVM的一些系统属性或者是定义在application.properties中的一些属性的值,因为其底层对应的是当前Environment对象。通过其shutdown()可以进行远程的关闭操作。

参考文档

https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/html/boot-features-spring-application.html

(注:本文是基于Spring Boot 2.0.3所写)

 

 

本文转自:http://elim.iteye.com/blog/2433113

分享到:
评论

相关推荐

    SpringBoot 源码解析 —— SpringApplication 源码分析.docx

    通过分析@SpringBootApplication 注解和 SpringApplication 类的 run 方法,我们可以了解 Spring Boot 应用程序的启动过程。 @SpringBootApplication 注解是一个组合注解,实际上它包含了多个注解,包括@...

    spring boot 深入浅出源码

    在深入理解Spring Boot的源码时,我们首先要明白其核心设计理念——“约定优于配置”。Spring Boot通过预设默认配置,使得开发者能够快速启动并运行应用,同时提供了丰富的启动器(Starters)来简化依赖管理。 ...

    Spring Boot参考指南.pdf

    - **使用Spring Boot**:详细介绍Spring Boot的基本用法,包括其核心特性和优势。 - **了解Spring Boot特性**:深入解析Spring Boot的关键特性,如自动配置、starter依赖等。 - **迁移到生产环境**:指导如何将...

    Spring Boot Aspect 切面 AOP 拦截器 Interceptor 监控control请求耗时

    在Spring Boot中,我们可以通过实现`HandlerInterceptor`接口并重写其三个方法——`preHandle()`, `postHandle()`, 和 `afterCompletion()` 来创建自定义的拦截器。 `preHandle()` 方法在目标处理方法调用之前执行...

    dubbo——与spring boot整合1

    import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; @...

    Spring Boot in Action-chapter 2 sample

    本章主要介绍如何利用Spring Boot快速启动一个项目,并通过实际案例深入理解Spring Boot自动配置的功能及其工作原理。 #### 二、核心知识点详解 ##### 1. Spring Boot Starters(启动器)的应用 Spring Boot通过...

    Spring Boot:启动原理解析.docx

    在深入探讨Spring Boot启动原理之前,首先需要理解的是Spring Boot的核心注解——`@SpringBootApplication`。这个注解是一个复合注解,包含了`@Configuration`、`@EnableAutoConfiguration`和`@ComponentScan`这三个...

    Spring Boot 视频

    接着,我们将深入研究Spring Boot的配置文件——`application.properties`或`application.yml`。这些文件允许开发者覆盖默认配置,定制化应用的行为。例如,你可以通过配置文件来指定数据库连接信息、服务器端口、...

    SpringBoot实战-清晰

    **Spring Boot实战——掌握核心概念与实践技巧** Spring Boot是由Pivotal团队开发的一个框架,旨在简化Spring应用的初始搭建以及开发过程。它通过提供预配置的“starter”依赖,使得开发者可以快速创建一个可运行的...

    spring-boot使用培训.pdf

    本培训文档旨在介绍Spring Boot的基础知识和使用方法,使初学者能够迅速掌握Spring Boot的入门技巧。 一、Spring Boot概述 Spring Boot是由Pivotal团队提供的一个开源项目,其设计目的是为了简化新Spring应用的...

    Spring Boot中的@Scheduled注解:定时任务的原理与实现

    Spring Boot作为一个流行的微服务开发框架,为开发者提供了一种简单而强大的方式来处理定时任务——即通过使用`@Scheduled`注解。本文将详细介绍`@Scheduled`注解的工作原理、配置方法以及如何在实际项目中运用它来...

    spring-cloud-eureka 服务注册及发现实例

    为了实现服务的注册,我们需要在 Spring Boot 的主类上添加 `@EnableEurekaClient` 注解,这样 Spring Boot 将会初始化 Eureka 客户端。 ```java @SpringBootApplication @EnableEurekaClient public class My...

    springboot - 2.7.3版本 - (三)整合Swagger3

    import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableSpringDocWebFlux public class Application { ...

    spring-boot-sample-tomcat:最最最简单得spring boot tomcat demo项目

    本篇文章将深入探讨如何使用Spring Boot与Tomcat进行最简单的集成,通过一个具体的demo项目——"spring-boot-sample-tomcat"来展示这一过程。 首先,Spring Boot的主旨是简化Spring应用的初始搭建以及开发过程。它...

    Spring Boot中配置定时任务、线程池与多线程池执行的方法

    在Spring Boot应用中,我们可以利用其提供的功能来配置和管理定时任务、线程池以及多线程池执行。这些配置对于构建高效、可扩展的应用至关重要,尤其是在处理并发和定时任务调度时。 首先,我们来看看如何配置基础...

    SpringBoot项目启动时实现调用一次初始化方法.docx

    在Spring Boot应用中,我们经常需要在项目启动时执行一次初始化操作,比如加载配置、预设数据等。这里我们将详细探讨如何实现这个需求,主要涉及`@PostConstruct`注解、`CommandLineRunner`接口以及在启动类中直接...

    java面试——SpringBoot面试专题.zip

    - **SpringApplication.run()**:这是启动Spring Boot应用的入口,它会创建ApplicationContext并加载配置。 - **SpringFactoriesLoader**:加载META-INF/spring.factories中的配置信息,初始化各种Spring Boot ...

    chapter01.zip

    《Spring Boot源代码解析——Chapter 01概览》 Spring Boot是Java开发中的一个热门框架,它简化了创建独立的、生产级别的基于Spring的应用程序的过程。本章将深入探讨"hello spring boot"项目的源代码,揭示其内在...

    spring加载

    Spring Boot通过`SpringApplication.run()`方法启动,自动配置Spring环境,加载 Starter POM 中声明的依赖。此外,Spring Boot的`@SpringBootApplication`注解整合了`@Configuration`,`@EnableAutoConfiguration`和...

    Java开发小程序.docx

    ### Java开发小程序——基于Spring Boot的后端API构建 #### 一、概述 本文将详细介绍如何使用Java语言结合Spring Boot框架来开发一个适用于小程序的后端API。在本项目中,我们将采用MyEclipse作为开发工具,并使用...

Global site tag (gtag.js) - Google Analytics