简介
可以用于从java主方法中引导和启动Spring应用程序的类,在默认情况下,通过以下步骤来启动应用:
创建一个ApplicationContext实例
注册CommandLinePropertySource用来暴露命令行参数作为spring的属性
refresh applicationContext,加载所有的singleton bean
触发任何CommandLineRunner bean
自定义SpringApplication
默认的启动方式,代码如下,不做深入介绍
1
SpringApplication.run(AppBoot1.class, args);
当然也可以做一些定制,如在Banner里面介绍的自定义banner,还有添加Listener等诸多设置,格式如下:
1 2 3
SpringApplication app = new SpringApplication(MySpringConfiguration.class); app.setBannerMode(Banner.Mode.OFF); app.run(args);
使用Fluent Builder API进行构建
先上代码,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
new SpringApplicationBuilder() .sources(ParentConfig.class) .child(Child1Config.class) .sibling(Child2Config.class) .banner(new AppBanner()) .logStartupInfo(false) .run(args);
//@Configuration
@PropertySource("classpath:/parent.properties") public class { }
// Child1Config.class
@PropertySource("classpath:/child1.properties") public class Child1Config {
}
// Child2Config.class
@PropertySource("classpath:/child2.properties") public class Child2Config {
}
使用SpringApplicationBuilder在构建分层的ApplicationContext应用的时候非常便利,但是官网给的代码示例很简单,对于一些初次介入的人可能理解上不是那么透彻。就上面的代码做一些简单的介绍
.sources(ParentConfig.class)该方法是用来配置父配置,或主配置的。但是有坑!!!!请看上面的ParentConfig的代码,注解我使用的是@SpringBootApplication,如果你使用的是springboot的1.x的版本,那么你会很顺利,如果你正在研究springboot 2.x的版本,你会发现无论如何也无法启动成功(我被坑的好惨)…。聪明的人也许看到我的注释,没错换成@Configuration之后就可以正常工作。但是很抱歉,这是为什么暂时还没找到原因,在github上请教暂时也没得到正确的结果,后面继续研究,如果有人发现了其中的原因,请通知我一下
.child(Child1Config.class)那么通过名字就可以看到是子环境了,Child1Config就是child1的配置文件。也许你的应用里有多个child,那么你可能会想用多个child().child(),那么这样你的第二个child不是parent的child,而是第一个child的child,parent的孙子。想要实现多个同级的孩子,可以使用代码中的.sibling(Child2Config.class)方法。这里同样存在一个springboot的版本改动问题,那就是如果你要在配置文件里面为child1配置一个context path,那么在版本1里面的方法是server.contextPath=child1
,但是如果使用版本2的朋友就需要做一点小改动了,改为server.servlet.contextPath=child1
可以参照github上的代码进行详细的理解github
事件和监听器
spring里面的监听器有三种实现方式:
@EventListener注解方式
实现ApplicationListener接口
实现SmartApplicationListener接口
上面三种方式代码分别为
1 2 3 4 5 6 7 8 9 10
@Component public class AnnotationRegisterListener {
@EventListener public void register(UserRegisterEvent event) { User user = event.getUser();
System.out.println("AnnotationRegisterListener " + user.getName() + ", " + user.getPassword()); } }
1 2 3 4 5 6 7 8 9 10 11
@Component public class RegisterListener implements ApplicationListener<UserRegisterEvent>{
@Override public void onApplicationEvent(UserRegisterEvent event) {
User user = event.getUser();
System.out.println("RegisterListener " + user.getName() + ", " + user.getPassword()); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
@Component public class UserRegisterListener implements SmartApplicationListener {
/** * 该方法返回true&supportsSourceType同样返回true时,才会调用该监听内的onApplicationEvent方法 * @param eventType * @return */ @Override public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { return UserRegisterEvent.class.isAssignableFrom(eventType); }
/** * 该方法返回true&supportsEventType同样返回true时,才会调用该监听内的onApplicationEvent方法 * @param sourceType * @return */ @Override public boolean supportsSourceType(@Nullable Class<?> sourceType) { return UserService.class.isAssignableFrom(sourceType); }
@Override public void onApplicationEvent(ApplicationEvent event) { UserRegisterEvent userRegisterEvent = (UserRegisterEvent) event; User user = userRegisterEvent.getUser(); System.out.println("UserRegisterListener " + user.getName() + ", " + user.getPassword()); }
/** * 同步情况下监听执行的顺序 * @return */ @Override public int getOrder() { return 3; } }
前两种实现方式比较简单,稍微介绍一下第三种,这种实现方式必须在supportsEventType和supportsSourceType同时返回true的情况下才会执行事件,具体如何返回true和false就看你自己的业务实现。在这里我使用了jdk的isAssignableFrom方法来判断父子关系的。 上面两种方式事件的执行顺序是无序的,第三种提供了一种指定属性的方法getOrder()
具体的isAssignableFrom是如何使用的,请看如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
public class Animal { }
public class Bird 大专栏 SpringBoot之SpringApplication n class="keyword">extends Animal implements Fly { }
public class Dove extends Bird { }
public class Penguin extends Bird { }
public interface Fly { }
public class Demo03 { public static void main(String[] args) {
assignOut(Animal.class, Animal.class); assignOut(Animal.class, Bird.class); assignOut(Bird.class, Animal.class); assignOut(Animal.class, Dove.class); assignOut(Penguin.class, Dove.class); assignOut(Fly.class, Bird.class); assignOut(Fly.class, Dove.class);
}
static void assignOut(Class cls1, Class cls2) { System.out.println(cls1.getSimpleName() + " isAssignableFrom " + cls2.getSimpleName() + " : " + cls1.isAssignableFrom(cls2)); } }
// 输出结果 Animal isAssignableFrom Animal : true Animal isAssignableFrom Bird : true Bird isAssignableFrom Animal : false Animal isAssignableFrom Dove : true Penguin isAssignableFrom Dove : false Fly isAssignableFrom Bird : true Fly isAssignableFrom Dove : true
SpringBoot启动过程中的事件及监听器
ApplicationStartingEvent 应用开始启动时执行,在初始化listeners and initializers之前执行
ApplicationEnvironmentPreparedEvent 环境准备好开始执行,上下文创建之前执行
ApplicationPreparedEvent 应用准备好开始执行,即所有bean都已经加载完毕之后,在refresh方法执行之前执行
ApplicationStartedEvent 应用启动后开始执行,即上下文被refreshed之后,任何的application和command-line runners调用前执行
ApplicationReadyEvent 应用启动完毕开始执行,任何的application和command-line runners调用后执行,从此后可以服务request了
ApplicationFailedEvent 启动时遇到异常执行
Listener的写法很简单,只以ApplicationStartingEvent为例,其他类似
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
public class MyApplicationStartedListener implements ApplicationListener<ApplicationStartedEvent> { @Override public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) { System.out.println("MyApplicationStartedListener..."); } }
在main方法注入 SpringApplicationBuilder builder = new SpringApplicationBuilder(); builder.listeners(new MyApplicationStartingListener()); builder.listeners(new MyApplicationEnvironmentPreparedListener()); builder.listeners(new MyApplicationPreparedListener()); builder.listeners(new MyApplicationStartedListener()); // builder.listeners(new MyApplicationReadyListener()); builder.sources(AppBoot.class); builder.run(args); 或者可以在META-INF/spring.factories中配置 org.springframework.context.ApplicationListener=com.smxknife.springboot.v2.ex03.listener.MyApplicationReadyListener
看一下输出结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
2018-03-03 01:24:06.387 INFO 5399 --- [ restartedMain] .ConditionEvaluationDeltaLoggingListener : Condition evaluation unchanged 2018-03-03 01:28:58.909 INFO 5399 --- [ Thread-28] ConfigServletWebServerApplicationContext : Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@58c49e73: startup date [Sat Mar 03 01:24:05 CST 2018]; root of context hierarchy 2018-03-03 01:28:58.913 INFO 5399 --- [ Thread-28] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown MyApplicationStartingListener... MyApplicationEnvironmentPreparedListener...
. ____ _ __ _ _ /\ / ___'_ __ _ _(_)_ __ __ _ ( ( )___ | '_ | '_| | '_ / _` | \/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |___, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.0.0.RC2)
2018-03-03 01:28:59.534 INFO 5399 --- [ restartedMain] com.smxknife.springboot.v2.ex03.AppBoot : Starting AppBoot on ShaoYundeMacBook-Pro.local with PID 5399 (/Users/ShaoYun/local/workstation/programs/smxknife/spring-boot/spring-boot-v2/spring-boot-v2-web/target/classes started by ShaoYun in /Users/ShaoYun/local/workstation/programs/smxknife/spring-boot) 2018-03-03 01:28:59.536 INFO 5399 --- [ restartedMain] com.smxknife.springboot.v2.ex03.AppBoot : No active profile set, falling back to default profiles: default MyApplicationPreparedListener... 2018-03-03 01:28:59.539 INFO 5399 --- [ restartedMain] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@45b78eb1: startup date [Sat Mar 03 01:28:59 CST 2018]; root of context hierarchy 2018-03-03 01:29:00.304 INFO 5399 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 10101 (http) 2018-03-03 01:29:00.305 INFO 5399 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2018-03-03 01:29:00.305 INFO 5399 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.28 2018-03-03 01:29:00.316 INFO 5399 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2018-03-03 01:29:00.317 INFO 5399 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 778 ms 2018-03-03 01:29:00.338 INFO 5399 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] 2018-03-03 01:29:00.338 INFO 5399 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] 2018-03-03 01:29:00.338 INFO 5399 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] 2018-03-03 01:29:00.338 INFO 5399 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] 2018-03-03 01:29:00.338 INFO 5399 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] 2018-03-03 01:29:00.492 INFO 5399 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@45b78eb1: startup date [Sat Mar 03 01:28:59 CST 2018]; root of context hierarchy 2018-03-03 01:29:00.529 INFO 5399 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/register]}" onto public java.lang.String com.smxknife.springboot.v2.ex03.web.controller.UserController.register(com.smxknife.springboot.v2.ex03.domain.User) 2018-03-03 01:29:00.533 INFO 5399 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 2018-03-03 01:29:00.534 INFO 5399 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) 2018-03-03 01:29:00.555 INFO 5399 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2018-03-03 01:29:00.555 INFO 5399 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2018-03-03 01:29:00.591 INFO 5399 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2018-03-03 01:29:00.648 INFO 5399 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729 2018-03-03 01:29:00.720 INFO 5399 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup 2018-03-03 01:29:00.738 INFO 5399 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 10101 (http) with context path '' 2018-03-03 01:29:00.739 INFO 5399 --- [ restartedMain] com.smxknife.springboot.v2.ex03.AppBoot : Started AppBoot in 1.585 seconds (JVM running for 3711.163) MyApplicationStartedListener... MyApplicationReadyListener... 2018-03-03 01:29:00.741 INFO 5399 --- [ restartedMain] .ConditionEvaluationDeltaLoggingListener : Condition evaluation unchanged
Listener的相关代码可以参照 github
SpringBoot之SpringApplication Explain
SpringApplication Explain The SpringApplication class provides a convenient way to bootstrap a Sprin ...
springboot自定义SpringApplication启动类
如果默认的SpringApplication不符合你的口味,你可以创建一个本地的实例并自定义它.例如,关闭banner你可以这样写: public static void main(String[] ...
入门到熟练-SpringBoot
Spring Boot概述 1.1. Spring Boot是什么 Spring Boot是一套基于Spring框架的微服务框架. 1.2. Spring Boot框架出现的背景 由于Spring是一 ...
[SpringBoot guides系列翻译]调度任务
原文 调度任务 用spring实现一个任务调度. 你将做的 你将做一个应用每5秒钟打印当前时间,用@Scheduled注解. 你需要啥 15分钟 文本编辑器或者IDE JDK1.8+ Gradle4+ ...
Spring-boot简单的理解
SpringBoot启动 SpringApplication.run(MyBootApplication.class); SpringApplication.run启动SpringBoot应用,主要过 ...
SpringBoot入门(1)
一.初始 ①.首先还是要创建一个maven工程 ②.然后编写Controller 让SpringBoot跑起来并不需要太多的代码,就能实现了我们平时要配置很多的功能,这是怎么做到的呢?我们就下面一个入 ...
SpringBoot 入门 Demo
SpringBoot 入门 Demo Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从 ...
idea实现第一个springboot程序
1.环境准备 JDK:1.8 Apache Maven: 3.6.1 IntelliJ IDEA 2019.1.3 x64 SpringBoot 1.5.9.RELEASE:1.5.9: 1.1.MA ...
自己动手实现springboot配置(非)中心
好久没写博客了,这段时间主要是各种充电,因为前面写的一些东西,可能大家不太感兴趣或者是嫌弃没啥技术含量,所以这次特意下了一番功夫.这篇博客其实我花了周末整整两天写好了第一个版本,已经开源出去了,同样是 ...
随机推荐
POJ-1679 The Unique MST(次小生成树、判断最小生成树是否唯一)
http://poj.org/problem?id=1679 Description Given a connected undirected graph, tell if its minimum s ...
kaggle——分销商产品未来销售情况预测
分销商产品未来销售情况预测 介绍 前面的几个实验中,都是根据提供的数据特征来构建模型,也就是说,数据集中会含有许多的特征列.本次将会介绍如何去处理另一种常见的数据,即时间序列数据.具体来说就是如何根据 ...
SAP AM:固定资产采购的预算管理
对于很多公司来说,购买资产是公司年度支持的主要部分,因此需要用预算管理来防止过度支出.这项支出被列为资本支出,所以很多公司都需要对购买过程和安全防范进行良好的控制.以下文中说明如何在购买资产时使用预算 ...
elasticsearch 大集群,双重别名,滚动更新分词方案
elasticsearch 滚动更新分词 国内用ik.hanlp.ansj或基于其二次开发的比较多 必然有分词变更的操作(主要是是加词) reindex+别名可以解决一部分问题,但在大集群上会影响业务 ...
【ccf- csp201412-2】z字形扫描
//ccf-Z字形扫描 #include<iostream> #include<cmath> using namespace std; #define N 500 int ma ...
linux特殊权限(acl)
建立用户目录 创建目录/oldboy/tech./oldboy/edu,分别用于不同项目组添加组账号 添加组账号tech.edu,GID分别设置为1001.1002 ...
一、安装Docker CE
卸载旧版本 较旧版本的Docker被称为docker或docker-engine.如果已安装这些,需要卸载以及相关的依赖项. $ sudo yum remove docker \ docker-cli ...
[LC] 40. Combination Sum II
Given a collection of candidate numbers (candidates) and a target number (target), find all unique c ...
[2015普及组-D]推销员 思维que
题:https://www.cometoj.com/problem/0221 #include<iostream> #include<cstring> #include< ...
线程中start和run方法的区别
先说java中实现多线程常用的两种方式: 1:继承Thread类,并重写run()方法 2:实现Runnable接口,实现run方法实际上Thread类也是实现了Runnable接口 [Jav ...