SpringApplication

它提供了一个方便的方法,通过 mian() 方法入口启动一个 Spring 项目,如下所示:

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

启动的时候,控制台输出如下欢迎页面:

  .   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.5.RELEASE)

这个图形是可以更改的,可以在类路径下面新建一个文件,名字必须是:banner.txt ,或者通过 spring.banner.location 属性配置,如果文件的编码不是 UTF8,可以通过 spring.banner.charset 属性设置编码;

这样该文件的内容就会被当做欢迎页面;



文件内容:



启动项目,欢迎页面:

Connected to the target VM, address: '127.0.0.1:56396', transport: 'socket'
a b
a b
a b
a b

此外,也可以选择图片当作欢迎页面,只是图片的名字必须是 banner ,还是将图片添加到类路径下面,或者通过 spring.banner.image.location 设置,这样图片就会被转为 ASCII 字符画 (博主,测试下不清楚,基本看不出原图片是啥);

关于欢迎页面,Spring 官网 给出了更多的设置,感兴趣,可以自己去看下,就不再介绍了;


SpringApplication 事件

除了平常的 Spring 事件,SpringApplication 还会发送一系列额外的应用事件;一些事件在 ApplicationContext 被创建之前发生,所以不能在 ApplicationContext 里面注册监听器,监听这些事件;

一般使用 SpringApplication.addListeners(…​) methodSpringApplicationBuilder.listeners(…​) 方法注册;

如果你想监听器被自动的注册,而不想去关心应用创建的方法,可以创建文件 META-INF/spring.factories 在里面引用监听器:

org.springframework.context.ApplicationListener=com.example.project.MyListener

相关的应用事件的顺序:

  1. ApplicationStartingEvent 在运行之前,监听器注册初始化以后,发生;
  2. ApplicationEnvironmentPreparedEvent 在上下文环境已经被使用之后,在上下文产生之前,发生;
  3. ApplicationPreparedEvent 在刷新之前,在加载 bean 之后,发生 ;
  4. ApplicationStartedEvent 在上下文刷新之后,在调用任何应用/命令行程序之前,发生;
  5. ApplicationReadyEvent 在调用任何应用/命令行程序之前,发生。它表示应用程序已经准备好为请求提供服务 ;
  6. ApplicationFailedEvent 在启动失败的时候,发生;

ApplicationContext 类型

SpringApplication 会试图去创建正确类型的 ApplicationContext

具体怎么确定正确类型的算法是很简单的e:

  1. 如果 SpringMvc 存在,则使用 AnnotationConfigServletWebServerApplicationContext
  2. 如果 SpringMvc 不存在,但是 Spring WebFlux 存在,则使用 AnnotationConfigReactiveWebServerApplicationContext
  3. 否则使用 AnnotationConfigApplicationContext

从中可以看出,SpringMvcSpring WebFlux 一起存在的时候,默认是按照 SpringMvc l来选取正确的类型的 ;

如果想更改,则自定义 SpringApplication 进行覆盖:

@SpringBootApplication
public class Application { public static void main(String[] args) {
// 自定义 SpringApplication
SpringApplication springApplication = new SpringApplication();
// 设置 ApplicationContext 类型
springApplication.setWebApplicationType(WebApplicationType); }
}

也可以调用 setApplicationContextClass() 方法,完全控制 ApplicationContext 类型;

如果使用 Junit 的时候,则把 ApplicationContext 的类型设置为 NONE

setWebApplicationType(WebApplicationType.NONE)

访问传递给 SpringApplication 的参数

我们获得传递 SpringApplication.run(...) 方法的参数,通过注入一个 org.springframework.boot.ApplicationArguments 对象;

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"]
} }

Spring BootSpring环境中注册了一个 CommandLinePropertySource 对象,这样,我们就可以使用 @Value 注解,向应用程序注入参数 ;


ApplicationRunner or CommandLineRunner

如果需要在SpringApplication 启动后运行一些特殊代码,我们可以通过实现 ApplicationRunner or CommandLineRunner 这两个接口中的一个,它们有着相同的工作方式,并且都有一个方法 run( ) ,这个方法在 SpringApplication.run(…​) 执行完成之前,被调用;

其中 CommandLineRunner 接口,将应用程序的参数,当作一组字符串数组:

@Component
class MyBean implements CommandLineRunner {
@Override
public void run(String... args) throws Exception { }
}

ApplicationRunner 则使用上面说的 org.springframework.boot.ApplicationArguments 对象 :

@Component
class MyBean implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception { }
}

如果有多个 CommandLineRunner or ApplicationRunner 对象被定义,并且他们需要安装一定的顺序得到执行,我们需要实现额外的接口 org.springframework.core.Ordered ,或者实现 org.springframework.core.annotation.Order 接口 ;

@Component
class MyBean implements ApplicationRunner,Order { @Override
public void run(ApplicationArguments args) throws Exception { } @Override
public int value() {
return 1;
} @Override
public Class<? extends Annotation> annotationType() {
return null;
}
}

或者直接使用注解:

@Order(value = 1)
class MyBean implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception { }
}

ExitCodeGenerator应用

每个 SpringApplication 都注册了一个 钩子JVM 中,确保在关闭 JVM 的时候,SpringApplication 可以正常退出;

Bean 还可以实现一个接口,org.springframework.boot.ExitCodeGenerator ,可以在应用程序退出的时候,返回一个我们自定义的状态码;

具体就是在 SpringApplication.exit() 被调用的时候,就会返回我们实现的接口中的状态码,然后传给 System.exit() 当中虚拟机退出的状态码;

@SpringBootApplication
public class Application implements ExitCodeGenerator { public static void main(String[] args) {
// SpringApplication.run(Application.class, args);
System.exit(SpringApplication.exit(SpringApplication.run(Application.class, args))); } @Override
public int getExitCode() {
return 10086;
} }

还可以把 ExitCodeGenerator 接口通过异常类实现,这样触发异常的时候,我们就在异常的构造器里面写上:

System.exit(SpringApplication.exit(上下文)));

就可以返回我们自定义的状态码 ;


配置文件

Spring Boot 允许我们进行许多的外部配置,以保证我们在不同的环境下运行代码,不需要要改动代码,只需要改动配置;

配置的值,可以使用@Value 注入到 Bean 里面,或者通过 @ConfigurationProperties 绑定到结构化的对象中;

配置文件配置的属性有先后关系,有覆盖关系,Spring Boot 的配置文件先后关系如下:

优先级从高到低:



获取配置文件中配置的属性值,比如获取 name 属性:

import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*; @Component
public class MyBean {
// 获取name属性
@Value("${name}")
private String name; // ... }
  • 配置随机数

    my.secret=${random.value}
    my.number=${random.int}
    my.bignumber=${random.long}
    my.uuid=${random.uuid}
    my.number.less.than.ten=${random.int(10)}
    my.number.in.range=${random.int[1024,65536]}

    我们可以将我们需要的一些随机数,配置在这里,前面四个,在程序运行期间只会产生一个相同的值,即一个程序多个访问,返回同一个随机值,重启程序以后,就会重新产生一个随机值;

    后面两个,每次都产生不同的随机数;

  • 获取命令行属性

    默认,SpringApplication 将命令行参数(即以 -- 开头的参数:--server.port = 9000),转化为属性,添加到 Spring 环境中;

    前面贴的图,上面标识了各个配置的优先级,其中命令行参数配置在第四个,优先于生产中使用的配置文件,因此,可以使用 SpringApplication.setAddCommandLineProperties(false). 禁止SpringApplication 将命令行参数,转化为属性 ;

  • application.properties 文件

    SpringApplication 会从下面几个地方加载配置;

    1、项目根文件夹下面的 config 文件夹

    2、项目根文件夹下面

    3、classpath 路径下面的 config 文件夹

    4、classpath 路径下面

    优先级,从高到低 ;

    也可以使用 application.yml 做配置文件`;


多个配置文件

默认的配置文件名字:application.properties/yml ,我们可以按照 application-【profile】.properties/yml 格式新建许多的配置文件;

但是新建出来的配置文件,必须和 application.properties/yml 放在一个文件夹下面,application.properties/yml 可以看成是配置文件的入口,我们自定义的配置文件,还需要在这里面使用 spring.profiles.active 进行引用一下(多文件之间用逗号分开):

spring.profiles.active=自定义配置文件名字(不加后缀)

这里记住,我们自定义的配置文件,总是会覆盖掉 application.properties/yml 里面的同名属性的,也就是优先级高于 application.properties/yml,前提是使用 spring.profiles.active 启用了我们自定义的配置文件;

至于多个自定义文件之间的优先级,spring.profiles.active 谁最后引用,谁优先级最高;

最后,多个配置文件,由于存在覆盖现象,其实最后加载的属性,就跟一个大的配置文件一样;


配置文件中的占位符

可以使用 ${}

name = 12
name11=${name}1

YAML 配置文件

官网推荐我们使用 .yml 替代使用 .properties

YAMLJSON 的超集,更适合表达配置之间的层级关系;

如果想要使用 YAML ,需要添加它的依赖 SnakeYAML ,如果使用了 spring-boot-starter 启动器,则默认添加了该依赖 ;

  1. 加载 YAML 文件

    首先 Spring Boot 默认会主动加载 src/main/resource 路径下,名字为: application.ymlyml 文件 ;

    此外,我们的 yml 文件放在其他地方,Spring 框架本身也提供了两种方法加载 YAML 文件,一种是利用 YamlPropertiesFactoryBeanYAML 加载为一个 Properties 对象,这种方式,将会将所有属性都当作String处理;

    如果上面的 YamlPropertiesFactoryBean 将所有属性都当作字符串,不能满足你的要求,那就用 YamlMapFactoryBeanYAML 加载为一个 Map 对象 ;

    YAML- 表示为下标:

    my:
    servers:
    - dev.example.com
    - another.example.com // 上面的 yml 格式,被转换为下面的形式 ; my.servers[0]=dev.example.com
    my.servers[1]=another.example.com

    示例代码,使用 YamlPropertiesFactoryBean 加载:

     // 加载YML格式自定义配置文件
    @Bean
    public static PropertySourcesPlaceholderConfigurer properties() {
    PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
    YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
    // 如果加载多个文件,则传入 ClassPathResource 数组
    yaml.setResources(new ClassPathResource("config/application-a.yml"));//class引入
    configurer.setProperties(yaml.getObject());
    return configurer;
    }
  2. 获取 yml 配置文件的属性值

    当我们加载过 yml 文件以后,还可以直接将配置文件中的属性绑定到 List Set 集合里面,通过Spring Boot@ConfigurationProperties 注解;

    写好 prefix 属性,它表示你要加载属性的前缀,然后还要保证 属性名字和 配置文件里面的一样 ,再为要获取的属性,添加对应的 setter 方法;

    比如要获取上面 yml 文件中的 services

    @Component
    @ConfigurationProperties(prefix = "my")
    public class Config { public void setServers(List<String> servers) {
    this.servers = servers;
    } private List<String> servers = new ArrayList<String>(); public List<String> getServers() {
    return this.servers;
    } }

    就可以将 yml文件中的 services 属性,封装到 list 集合里面,这是一种获取配置文件属性的方法;

    还可以通过使用 @Value 注解,访问 yml 配置文件的属性,但是要写配置文件中的key 的全部名称 :

     @Value("${number.int.five}")
    private int num ;
  3. 全局化 yml 属性

    官网说可以使用 YamlPropertySourceLoader 来加载 yml 文件,然后添加到 Spring 环境中:

    package hello.config;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.env.EnvironmentPostProcessor;
    import org.springframework.boot.env.YamlPropertySourceLoader;
    import org.springframework.core.env.ConfigurableEnvironment;
    import org.springframework.core.env.PropertySource;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource; import java.io.IOException; public class EnvironmentPostProcessorExample implements EnvironmentPostProcessor { private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader(); @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment,
    SpringApplication application) {
    // 路径记得改为你自己的路径
    Resource path = new ClassPathResource("config/application.yml");
    PropertySource<?> propertySource = loadYaml(path);
    environment.getPropertySources().addLast(propertySource);
    } private PropertySource<?> loadYaml(Resource path) {
    if (!path.exists()) {
    throw new IllegalArgumentException("Resource " + path + " does not exist");
    }
    try {
    return this.loader.load("custom-resource", path).get(0);
    } catch (IOException ex) {
    throw new IllegalStateException(
    "Failed to load yaml configuration from " + path, ex);
    }
    } }

    然后还需要配置一个东西:



    class path 路径下面,新建 /META-INF/spring.factories 文件,在里面注册下我们刚刚的类:

    org.springframework.boot.env.EnvironmentPostProcessor=hello.config.EnvironmentPostProcessorExample

    我没发现,和自己自定义加载有什么不同。没搞懂 Spring 环境是什么意思;

  4. 一个 yml 文件配置多个部分属性

    我们可以使用 spring.profiles 键,作为分割,在一个文件里面,配置多个场景属性:

    YAML 中使用 --- 分割不同部分;

    server:
    address: 192.168.1.100
    ---
    spring:
    profiles: development
    server:
    address: 127.0.0.1
    ---
    spring:
    profiles: production & eu-central
    server:
    address: 192.168.1.120

    比如上面的配置,当 profilesdevelopment 的时候,IP127.0.0.1;当 profilesproduction & eu-central 的时候,IP192.168.1.120;当 profiles 既不是 development,也不是 production & eu-central 的时候,IP192.168.1.100

    这里的 spring: profiles: 的值是个表达式,具体支持符号有 ()|& ,如果要混用 & | 必须使用 () ,比如 : production & us-east | eu-central 不是有效的表达式。它必须表达为 production & (us-east | eu-central)

    还可以配置一个默认的配置,如果项目启用以后没有特殊配置,则选用这个默认的,比如,配置一个默认米密码:

    server:
    port: 8000
    ---
    spring:
    profiles: default
    security:
    user:
    password: weak

    这里一定要写上 profiles: default,否则就不是默认配置了,就是妥妥的配置,选用其它配置,密码还会是 weak 的;

    profiles 不要产生二义性

  5. 缺点

    官网原文如下:

    24.7.4 YAML Shortcomings

    YAML files cannot be loaded by using the @PropertySource annotation. So, in the case that you need to load values that way, you need to use a properties file.

    说我们不能再使用 @PropertySource 注解,加载 YAML 文件了,@PropertySource 只能用来加载 .properties 文件了 ;


(五)Spring Boot官网文档学习的更多相关文章

  1. (四)Spring Boot官网文档学习

    文章目录 关于默认包的问题 加载启动类 配置 Bean管理和依赖注入 @SpringBootApplication Developer Tools 关于 Developer Tools 的一些细节 原 ...

  2. (三)Spring Boot 官网文档学习之默认配置

    文章目录 继承 `spring-boot-starter-parent` 覆盖默认配置 启动器 原文地址:https://docs.spring.io/spring-boot/docs/2.1.3.R ...

  3. (二)Spring Boot 官网文档学习之入门

    文章目录 Spring Boot 是什么 系统要求 Servlet 容器 Maven方式安装Spring Boot 编写第一个 Spring Boot 项目 原文:https://docs.sprin ...

  4. Spring Security 官网文档学习

    文章目录 通过`maven`向普通的`WEB`项目中引入`spring security` 配置 `spring security` `configure(HttpSecurity)` 方法 自定义U ...

  5. Spring3.0官网文档学习笔记(八)--3.4.3~3.4.6

    3.4.3 使用depends-on     使用depends-on能够强制使一个或多个beans先初始化,之后再对这个bean进行初始化. 多个bean之间用","." ...

  6. Spring3.0官网文档学习笔记(一)

    Part 1 Spring框架概述 Spring是模块化的,在应用中仅仅须要引入你所须要用到的模块的jar包,其余的jar包不用引入. spring框架支持声明式的事务管理,通过RMI或web ser ...

  7. Spring3.0官网文档学习笔记(七)--3.4.2

    3.4.2 依赖与配置的细节     3.4.2.1  Straight values (primitives, Strings, and so on)     JavaBeans PropertyE ...

  8. Spring3.0官网文档学习笔记(二)

    1.3 使用场景 典型的成熟的spring web应用 spring使用第三方框架作为中间层 远程使用场景 EJB包装 1.3.1 依赖管理.命名规则(包)     spring-*.jar *号代表 ...

  9. Spring3.0官网文档学习笔记(四)--3.1~3.2.3

    3.1 Spring IoC容器与Beans简单介绍     BeanFactory接口提供对随意对象的配置:     ApplicationContext是BeanFactory的子接口.整合了Sp ...

随机推荐

  1. CSS3 clip-path & clip-path 打破矩形设计的限制

    CSS 形状模块标准1(CSS Shapes Module Level 1)这个规范打破了 WEB 中的矩形盒模型的限制,并且将网页设计提升到一个新的高度. 关于 Shapes 规范 shape-ou ...

  2. 第10组 Alpha冲刺(2/6)

    链接部分 队名:女生都队 组长博客: 博客链接 作业博客:博客链接 小组内容 恩泽(组长) 过去两天完成了哪些任务 描述 了解了如何根据系统获取的实际情况进行后端任务的调整 网易云音乐推荐算法的分析 ...

  3. Gated CNN 阅读笔记

    之前看过TCN,稍微了解了一下语言模型,这篇论文也是对语言模型建模,但是由于对语言模型了解不深,一些常用数据处理方法,训练损失的计算包括残差都没有系统的看过,只是参考网上代码对论文做了粗浅的复现.开学 ...

  4. 在java的Map集合中,怎样更改value的值

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/chenyao1994/article/de ...

  5. QTextToSpeech Win7奔溃

    在linux下,它是调用speech-dispatcher.在其它不同的平台上,调用各自平台的TTS引擎.所以在使用的时候,要确保本地的TTS引擎是可用的. 本地TTS引擎不可用可能会在声明QText ...

  6. RNA剪接体 Spliceosome | 冷冻电镜 | 结构生物学

    冷冻电镜 为什么冷冻电镜 (Cryo-EM) 技术的发明可以获得2017诺贝尔化学奖?知乎看法 Press release: The Nobel Prize in Chemistry 2017 We ...

  7. Learning Conditioned Graph Structures for Interpretable Visual Question Answering

    Learning Conditioned Graph Structures for Interpretable Visual Question Answering 2019-05-29 00:29:4 ...

  8. sublime text3中如何使用PHP编译系统

     [WinError 2] 系统找不到指定的文件 编译错误原因,是因为编译器没有配置 第一步: 添加php可执行程序所在目录到系统环境变量(具体方法此处省略,使用本文下面的说明中的方法,此步骤可以省略 ...

  9. python自动化登录获取图片登录验证码

    主要记录一下:图片验证码1.获取登录界面的图片2.获取验证码位置3.在登录页面截取验证码保存4.调用百度api识别(目前准确率较高的识别图片api)本次登录的系统页面,可以看到图片验证码的位置登录页面 ...

  10. 廖雪峰Git教程2

    转自:https://www.liaoxuefeng.com/wiki/896043488029600 [远程仓库] 到目前为止,我们已经掌握了如何在Git仓库里对一个文件进行时光穿梭,你再也不用担心 ...