SpringApplication理解
Posted maxudong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringApplication理解相关的知识,希望对你有一定的参考价值。
SpringApplication提供了一种很方便的方式来启动spring 应用,通过使用main()方法。在很多情况下,你可以使用SpringApplication.run静态方法来委托实现;如下:
@SpringBootApplication public class SampleApplication { public static void main(String[] args) { SpringApplication.run(SampleApplication.class, args); } }
项目启动后,如下图所示:默认情况下,显示INFO级别的日志信息,包括相关的启动详情,如springboot版本号、用户名、主机名、进程ID、项目路径、servlet容器、及项目路径等基本信息。
1.如果你想把日志级别设为其他,可以修改application.properties中配置,如下:
logging.level.root=warn logging.level.org.springframework.web=debug logging.level.org.hibernate=error
2.如果你想关闭启动日志,可以设置application.properties中的spring.main.log-startup-info为false;
spring.main.log-startup-info=false
3.在项目启动时,你可以通过重写SpringApplication子类的logStartupInfo(boolean)来添加额外的日志信息;
1.1启动失败:
如果应用启动失败,FailureAnalyzers会提供一个专用的错误描述和具体的解决问题的Action。例如:如果你在8080端口启了一个web应用,而这个端口已经被占用,你就可以看到下图所示的信息:
注意:Spring Boot提供了大量的FailureAnalyzer实现,你也可以自定义实现。
如果遇到failure analyzers不能处理的异常,你可以展示完整的conditions report以便于更好的理解错误。如使用DEBUG日志级别,或者使用java -jar,并启用debug模式:
java -jar myproject-0.0.1-SNAPSHOT.jar --debug
1.2懒初始化(Lazy Initialization)
懒初始化:beans在需要的时候才被创建,而不是在应用启动时;默认情况下,禁用懒加载;如果使用懒加载,必须保证JVM有足够的内存;
优点:启用懒初始化会减少应用启动的时间。在一个web应用中,懒加载会使很多web相关的beans在接收到Http请求的时候才被初始化;
缺点:延迟发现应用的问题。如果一个配置错误的bean被懒加载,这个错误不会在项目启动时出现,而是在该bean初始化时才被发现;
设置懒加载的方式:
1.编程方式:使用SpringApplicationBuilder的lazyInitialization方法或者是SpringApplication的setLazyInitialization方法;
2.配置方式:spring.main.lazy-initialization=true
3.当启用懒加载模式时,可以使用@Lazy(false)注解为指定beans禁用懒加载;
1.3自定义Banner
默认Banner:Banner会在项目启动时被打印在开头;spring boot自带的Banner在SpringBootBanner类中定义,如下图所示:
/** * Default Banner implementation which writes the \'Spring\' banner. * */ class SpringBootBanner implements Banner { private static final String[] BANNER = { "", " . ____ _ __ _ _", " /\\\\\\\\ / ___\'_ __ _ _(_)_ __ __ _ \\\\ \\\\ \\\\ \\\\", "( ( )\\\\___ | \'_ | \'_| | \'_ \\\\/ _` | \\\\ \\\\ \\\\ \\\\", " \\\\\\\\/ ___)| |_)| | | | | || (_| | ) ) ) )", " \' |____| .__|_| |_|_| |_\\\\__, | / / / /", " =========|_|==============|___/=/_/_/_/" }; private static final String SPRING_BOOT = " :: Spring Boot :: "; private static final int STRAP_LINE_SIZE = 42; ...... }
自定义banner:
1.文本Banner:可以通过在classpath路径下添加banner.txt文件或者设置spring.banner.location属性来指定自定义Banner文件;如果文件格式不是UTF-8,可以设置spring.banner.charset属性
2.图片Banner:在classpath路径下添加banner.gif、banner.jpg、banner.png图片或者通过spring.banner.image.location属性来指定文件;效果如下所示:
3.编程方式:SpringApplication.setBanner(…)使用编程的方式设置banner,使用org.springframework.boot.Banner接口实现printBanner()方法;
注意:图片转化为ASCII 艺术展示;而且显示在文本Banner上方;banner.txt文件中你可以使用如下的占位符;可以使用spring.main.banner-mode来设置是否将banner打印在控制台上(log/off);banner会被注册为单个的bean,名为springBootBanner;
${application.version}:应用版本号 ${application.formatted-version}:格式化后的应用版本号,加括号及前缀“v”,例如:(v1.0) ${spring-boot.version}:spring boot的版本号,如2.2.2.RELEASE ${spring-boot.formatted-version}:格式化后的spring boot的版本号,如(v2.2.2.RELEASE)
...
1.4自定义SpringApplication
如果默认的SpringApplication不符合你的口味,你可以创建一个本地实例并自定义它。例如,你可以使用以下代码关闭banner:
public static void main(String[] args) { SpringApplication app = new SpringApplication(MySpringConfiguration.class); app.setBannerMode(Banner.Mode.OFF); app.run(args); }
注意:SpringApplication构造器参数是spring beans的configuration源。大多数情况下,这些configuration源和@Configuration注解的类有关,也有可能和XML配置或者是被扫描的包有关;
也可以使用application.properties文件来配置SpringApplication,详细内容可以查看SpringApplication JavaDoc
1.5 SpringApplicationBuilder
如果你需要构建ApplicationContext层次结构(带有父/子的多个上下文关系),或者如果您更喜欢使用“Builder API,则可以使用SpringApplicationBuilder。SpringApplicationBuilder允许使用方法链的方式来创建ApplicationContext层次结构,包括parent、child,如下所示:
new SpringApplicationBuilder() .sources(Parent.class) .child(Application.class) .bannerMode(Banner.Mode.OFF) .run(args);
注意:创建ApplicationContext层级结构有一些限制条件。比如,Web组件必须存在于子上下文,而且父和子上下文使用相同的Environment。SpringApplicationBuilder JavaDoc
1.6 Application Events and Listeners
除了通常的Spring框架事件(例如ContextRefreshedEvent)之外,SpringApplication还发送一些额外的应用程序事件。
注意:实际上在创建ApplicationContext之前会触发一些事件,因此我们无法将这些监听器(Listeners)注册为@Bean。你可以通过SpringApplication.addListeners(…)或SpringApplicationBuilder.listeners(…)方法来注册监听器; 如果你不关心应用的创建方式,只希望这些监听器被自动注册,你可以在项目中添加一个 META-INF/spring.factories文件,并在文件中指定监听器的引用,如下所示:
org.springframework.context.ApplicationListener=com.example.project.MyListener
应用程序运行时事件按以下顺序发送:
- ApplicationStartingEvent:程序启动但未执行任何处理(不包括listeners和initializers注册);
- ApplicationEnvironmentPreparedEvent:Environment被上下文使用但是上下文未创建前;
- ApplicationContextInitializedEvent:ApplicationContext准备完成 并且 调用ApplicationContextInitializers,但bean定义被加载之前;
- ApplicationPreparedEvent:bean定义被加载后 但 应用上下文未刷新完成前;
- ApplicationStartedEvent:上下文刷新完成,但 应用程序和命令行程序被吊起之前;
- ApplicationReadyEvent:所有应用程序和命令行启动程序被吊起之后,将发送一个ApplicationReadyEvent。 它指示该应用程序已准备就绪,可以处理请求。
- ApplicationFailedEvent:程序启动出现异常;
上述列表中的SpringApplicationEvents仅仅是和SpringApplication绑定的;除了这些,介于ApplicationPreparedEvent和ApplicationStartedEvent之间的event还有下列:
- ContextRefreshedEvent:当ApplicationContext刷新时;
- WebServerInitializedEvent:WebServer准备完成时;ServletWebServerInitializedEvent和ReactiveWebServerInitializedEvent分别表示servlet应用(MVC)和reactive(webflux)应用;
注意:我们可能用不到这些应用事件,但是知道它们的存在以后处理问题可能会很方便。Spring Boot使用应用事件可以处理各式各样的任务。
应用程序事件是通过使用Spring Framework的事件发布机制发送的。 这样的机制确保将在子上下文中发布给监听器的事件也发布到在任何祖先上下文中的监听器。 因此,如果你的应用程序是有多个SpringApplication实例的分层结构时,监听器可能会收到多个实例的相同类型的应用程序事件。
不是很理解,慢慢理解:To allow your listener to distinguish between an event for its context and an event for a descendant context, it should request that its application context is injected and then compare the injected context with the context of the event. The context can be injected by implementing ApplicationContextAware or, if the listener is a bean, by using @Autowired.
1.7Web Environment
SpringApplication总是会创建一个正确的ApplicationContext,决定WebApplicationType的算法很简单;
- 如果当前项目是spring mvc项目,将会使用AnnotationConfigServletWebServerApplicationContext;
- 如果当前项目是spring webflux项目,将会使用AnnotationConfigReactiveWebServerApplicationContext;
- 其他情况下,使用AnnotationConfigApplicationContext;
1.8Accessing Application Arguments
你可以通过注入org.springframework.boot.ApplicationArguments bean的方式使用SpringApplication.run(…)方法中的参数,即Application Arguments;如下,项目启动时,会在控制台输出args的内容!
@SpringBootApplication public class SampleApplication { public static void main(String[] args) { args = new String[]{"111","222"}; SpringApplication.run(SampleApplication.class, args); } @Autowired public SampleApplication(ApplicationArguments args) { List<String> files = args.getNonOptionArgs(); for(String str:files){ System.out.println(str); } } }
注意:spring boot在spring Environment.中注册了一个CommandLinePropertySource,它允许你使用@Value注解的方式注入单个application arguments;
1.9 使用ApplicationRunner或CommandLineRunner
一旦SpringApplication启动后,如果你想运行一些特殊的代码,你可以通过实现ApplicationRunner或CommandLineRunner接口的方式实现;两个接口工作方式相同,都只有一个run方法,在SpringApplication.run(…)完成前调用;使用方式如下:
@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 annotation注解;
1.10 Application Exit
Each SpringApplication registers a shutdown hook with the JVM to ensure that the ApplicationContext closes gracefully on exit. All the standard Spring lifecycle callbacks (such as the DisposableBean interface or the @PreDestroy annotation) can be used. In addition, beans may implement the org.springframework.boot.ExitCodeGenerator interface if they wish to return a specific exit code when SpringApplication.exit() is called. This exit code can then be passed to System.exit() to return it as a status code, as shown in the following example:
@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))); } }
Also, the ExitCodeGenerator interface may be implemented by exceptions. When such an exception is encountered, Spring Boot returns the exit code provided by the implemented getExitCode() method.
以上是关于SpringApplication理解的主要内容,如果未能解决你的问题,请参考以下文章
微服务 SpringBoot 2.0:启动剖析之SpringApplication.run