• (五)Spring Boot官网文档学习



    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 文件了 ;


  • 相关阅读:
    python 3.5下用户登录验证,三次锁定的编码
    Python之面向对象
    Python基础之模块
    Python基础之yield,匿名函数,包与re模块
    Python基础之函数
    Python基础之字符编码,文件操作流与函数
    Python基础之字符串,布尔值,整数,列表,元组,字典,集合
    Python基础之(判断,循环,列表,字典)
    mysql学习
    linux 下的 正则表达式(awk,sed,awk)学习
  • 原文地址:https://www.cnblogs.com/young-youth/p/11665588.html
Copyright © 2020-2023  润新知