五Spring Application那些事儿
Posted 编程新鲜事
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了五Spring Application那些事儿相关的知识,希望对你有一定的参考价值。
SpringApplication类提供了一种快捷方式来启动Java程序,可以从main()方法启动Spring应用。有没有觉得很简单,很方便。 接下来将带你学习一些其他的一些关于SpringApplication东东
Spring Boot启动
SpringApplication类提供了一种快捷方式,用于从main()方法启动Spring应用。多数情况下,你只需要将该任务委托给SpringApplication.run静态方法:
public static void main(String[] args){
SpringApplication.run(MySpringConfiguration.class, args);
}
当应用启动时,你应该会看到类似下面的东西:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.4.RELEASE)
2019-05-13 17:54:38.616 INFO 2851 --- [ main] com.sz.demo.mall.MallApplication : Starting MallApplication on jxmac-mini with PID 2851 (/Users/jaime/Documents/gitproject/SZMall/target/classes started by jaime in /Users/jaime/Documents/gitproject/SZMall)
2019-05-13 17:54:38.620 INFO 2851 --- [ main] com.sz.demo.mall.MallApplication : No active profile set, falling back to default profiles: default
2019-05-13 17:54:39.750 INFO 2851 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-05-13 17:54:39.883 INFO 2851 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-05-13 17:54:39.883 INFO 2851 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-05-13 17:54:40.508 INFO 2851 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-05-13 17:54:40.508 INFO 2851 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1826 ms
2019-05-13 17:54:40.683 INFO 2851 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-05-13 17:54:40.906 INFO 2851 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-05-13 17:54:40.909 INFO 2851 --- [ main] com.sz.demo.mall.MallApplication : Started MallApplication in 2.926 seconds (JVM running for 5.233)
默认情况下,会显示INFO日志消息,包括一些相关的启动细节,比如启动应用程序的用户。如果您需要一个除INFO以外的日志级别,您可以设置它,如第264节所述,“日志级别”, 如果你想修改Spring log的默认级别可以在application.properties: logging.level.root=WARN logging.level.org.springframework.web=DEBUG logging.level.org.hibernate=ERROR 如果你想看debug信息,你也可以这样:
java -jar myproject-0.0.1-SNAPSHOT.jar --debug
注意:当然如果全都是debug级别的话,启动的速度会稍微慢点,因为会线程阻塞住进行log输出
自定义输出
通过在classpath下添加一个banner.txt或设置pring.banner.location来指定相应的文件可以改变启动过程中打印的banner。如果这个文件有特殊的编码,你可以使用banner.encoding设置它(默认为UTF-8)。如果文件不是UTF-8的编码,您可以设置spring.banner.charset。除了文本文件,你也可以添加一个banner.gif,banner.jpg或banner.png图片,或设置spring.banner.image.location属性。图片会转换为字符画(ASCII art)形式,并在所有文本banner上方显示。 在banner.txt中可以使用如下占位符:
变量 | 描述 |
---|---|
${application.version} | MANIFEST.MF中声明的应用版本号,例如Implementation-Version: 1.0会打印1.0 |
${application.formatted-version} | MANIFEST.MF中声明的被格式化后的应用版本号(被括号包裹且以v作为前缀),用于显示,例如(v1.0) |
${spring-boot.version} | 当前Spring Boot的版本号,例如2.0.5.RELEASE |
${spring-boot.formatted-version} | 当前Spring Boot被格式化后的版本号(被括号包裹且以v作为前缀), 用于显示,例如(v2.0.5.RELEASE) |
${Ansi.NAME}(或${AnsiColor.NAME},${AnsiBackground.NAME}, ${AnsiStyle.NAME}) | NAME代表一种ANSI编码,具体详情查看AnsiPropertySource |
${application.title} | MANIFEST.MF中声明的应用title,例如Implementation-Title: MyApp会打印MyApp |
注 如果想以编程的方式产生一个banner,可以使用SpringBootApplication.setBanner(…)方法,并实现org.springframework.boot.Banner接口的printBanner()方法。 你也可以使用spring.main.banner-mode属性决定将banner打印到何处,System.out(console),配置的logger(log)或都不输出(off)。 打印的banner将注册成一个名为springBootBanner的单例bean。注 YAML会将off映射为false,如果想在应用中禁用banner,你需要确保off添加了括号:
spring:
main:
banner-mode: "off"
流式(Builder)模式启动Spring Boot
如果需要创建一个分层的ApplicationContext(多个具有父子关系的上下文),或只是喜欢使用流式(fluent)构建API,那你可以使用SpringApplicationBuilder。 SpringApplicationBuilder允许你以链式方式调用多个方法,包括parent和child方法,这样就可以创建多层次结构,例如:
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
Spring Boot事件
除了常见的Spring框架事件,比如ContextRefreshedEvent,SpringApplication也会发送其他的application事件。 应用运行时,事件会以下面的次序发送:
在运行开始,但除了监听器注册和初始化以外的任何处理之前,会触发一个ApplicationStartingEvent。
在Environment将被用于已知的上下文,但在上下文被创建前,会出发一个ApplicationEnvironmentPreparedEvent。
在refresh开始前,但在bean定义已被加载后,会触发一个ApplicationPreparedEvent。
在context被刷新之后,但是在任何应用程序和命令行运行者被调用之前,会出发ApplicationStartedEvent
在任何应用程序和命令行运行程序被调用之后,都会触发一个ApplicationReadyEvent。它表明应用程序已经准备好服务请求。
如果在启动时出现异常,则会触发ApplicationFailedEvent 。
注*:*通常不需要使用application事件,但知道它们的存在是有用的(在某些场合可能会使用到),比如,在Spring Boot内部会使用事件处理各种任务。Application Event是通过使用Spring Framework的事件发布机制发送的。这种机制的一部分确保在任何祖先上下文中向侦听器发布给侦听器的事件也被发布给侦听器。因此,如果您的应用程序使用SpringApplication实例的层次结构,侦听器可能会收到同一类型的应用程序事件的多个实例。 为了让您的侦听器能够区分其上下文的事件和后代上下文的事件,它应该请求注入它的应用程序上下文,然后将注入的上下文与事件的上下文进行比较。通过使用@Autowired,可以通过实现ApplicationContextAware来注入,或者,如果监听器是bean的话。
注:有些事件实际上是在ApplicationContext创建前触发的,所以你不能在那些事件(处理类)中通过@Bean注册监听器,只能通过SpringApplication.addListeners(…)或SpringApplicationBuilder.listeners(…)方法注册。如果想让监听器自动注册,而不关心应用的创建方式,你可以在工程中添加一个META-INF/spring.factories文件,并使用org.springframework.context.ApplicationListener作为key指向那些监听器,如下:
org.springframework.context.ApplicationListener=com.example.project.MyListener
或者可以写在代码里:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.addListeners(new ApplicationEnvironmentPreparedEventListener());
app.addListeners(new ApplicationFailedEventListener());
app.run(args);
}
}
在Spring Boot中获取启动参数
如果需要获取传递给SpringApplication.run(…)的应用参数,你可以注入一个org.springframework.boot.ApplicationArguments类型的bean。ApplicationArguments接口即提供对原始String[]参数的访问,也提供对解析成option和non-option参数的访问:
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"]
}
}
启动加载数据 CommandLineRunner或者ApplicationRunner
实际应用中,我们会有在项目服务启动的时候就去加载一些数据,Spring Boot 为我们提供了一个方法,通过实现接口 CommandLineRunner 来实现。 创建实现接口 CommandLineRunner 的类
@Component
public class InitDataRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.err.println("InitDataRunner ....");
}
}
如果某些定义的CommandLineRunner或ApplicationRunner beans需要以特定的顺序调用,你可以实现org.springframework.core.Ordered接口或使用org.springframework.core.annotation.Order注解。
Application退出
SpringApplication都向JVM注册一个关机钩子,以确保ApplicationContext在出口处优雅地关闭。可以使用所有标准的Spring生命周期回调(如一次性的sablebean接口或@pre销毁注释)。 此外,bean还可以实现org.springframework.boot。如果他们希望在SpringApplication.exit()被调用时返回一个特定的出口代码,ExitCodeGenerator接口。然后,这个退出码可以被传递给system.exit(),以作为状态码返回它。
@Component
public class MyExitCodeGenerator implements ExitCodeGenerator {
@Override
public int getExitCode() {
System.err.println("----9999------ shutdown--------");
return 999;
}
}
@RestController
public class HelloController {
@Autowired
private ApplicationContext applicationContext;
@GetMapping("/stop")
public String stop() {
// 加上自己的权限验证,密码啊,加密啊,时间啊啊等等
SpringApplication.exit(applicationContext);
return "ok";
}
}
以上是关于五Spring Application那些事儿的主要内容,如果未能解决你的问题,请参考以下文章