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()
可以进行远程的关闭操作。
参考文档
(注:本文是基于Spring Boot 2.0.3所写)
相关推荐
适合初学者spring-boot——web笔记
日志,通常不会在需求阶段作为一个功能单独提出来,也不会在产品方案中看到它的细节。但是,这丝毫不影响它在任何一个系统中的重要的地位。 为了保证服务的高可用,发现问题一定要即使,解决问题一定要迅速,所以...
Spring Boot中配置文件介绍及其使用教程所用到的Controller代码 Spring Boot中配置文件介绍及其使用教程所用到的Controller代码 Spring Boot中配置文件介绍及其使用教程所用到的Controller代码 Spring Boot中配置...
spring boot整合JPA——demo
Spring boot——@DeclareParents例子...
Spring Boot简化了基于Spring的应用开发,通过少量的代码就能创建一个独立的、产品级别的Spring应用。Spring Boot为Spring平台及第三方库提供开箱即用的设置,这样你就可以有条不紊地开始。多数Spring Boot应用只...
spring-boot-helloWorld:spring-boot的helloWorld版本 spring-boot-mybaits-annotation:注解版本 spring-boot-mybaits-xml:xml配置版本 spring-boot-mybatis-mulidatasource:springboot+mybatis多数据源最简解决...
java毕业设计——基于spring boot的就业信息管理网站设计与实现(源码+数据库).zip java毕业设计——基于spring boot的就业信息管理网站设计与实现(源码+数据库).zip java毕业设计——基于spring boot的就业信息管理...
获取Spring Boot 2微框架的可重用代码配方和代码段 了解Spring Boot 2如何与其他Spring API,工具和框架集成 访问Spring MVC和新的Spring Web Sockets,以实现更简单的Web开发 使用微服务进行Web服务开发并与Spring ...
基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring ...
基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 ...
Beginning Spring Boot 2 Beginning Spring Boot 2 Beginning Spring Boot 2
介绍一个基于Spring Boot 3.0、Spring Cloud 2022 & Alibaba的微服务RBAC权限管理系统。该系统可以实现微服务RBAC权限管理,通过RBAC权限管理机制对用户访问系统的权限进行限制,从而提高系统的安全性和可用性。同时...
java毕业设计——基于spring boot的音乐播放网站设计与实现(源码+数据库).zip java毕业设计——基于spring boot的音乐播放网站设计与实现(源码+数据库).zip java毕业设计——基于spring boot的音乐播放网站设计与...
《Vue Spring Boot前后端分离开发实战》源码 Vue+Spring Boot前后端分离开发实战教学课件(PPT)
Spring Boot视频教程大合集,完美帮助你学习Spring Boot,内部有3套Spring Boot学习视频教程,另附一篇Security Oauth2.0认证授权视频教程
本课程内容包括Spring简介、Spring Boot简介、安装JDK、安装Maven、第一个Spring Boot程序(使用Spring Initializr构建、Spring Boot代码讲解、安装Notepad++)、构建系统、代码、配置、三种方式运行程序、安装...
Pro Spring Boot is your authoritative hands-on practical guide for increasing your Spring Framework-based enterprise Java and cloud application productivity while decreasing development time using the...
Spring Boot 最佳实践.pdf Spring Boot 最佳实践.pdf Spring Boot 最佳实践.pdf Spring Boot 最佳实践.pdf Spring Boot 最佳实践.pdf Spring Boot 最佳实践.pdf