zoukankan      html  css  js  c++  java
  • Spring Boot笔记二:Spring Boot配置文件

    二、Spring Boot与配置

    1、配置文件

    SpringBoot使用一个全局配置文件,配置文件名是固定的:

    	- application.properties
    	- application.yml
    

    配置文件的作用:修改SpringBoot的默认配置,SpringBoot在底层已经配置好了

    YAML(Ain't Markup Language)

    ​ YAML A Markup Language:是一个标记语言

    ​ YAML Isn't Markup Language:不是是一个标记语言

    标记语言:

    ​ 以前的配置文件:大多数都使用的是xxx.xml文件

    ​ YAML:以数据为中心,比json、xml等更适合做配置文件

    ​ YAML:配置例子

    server:
      port: 8081
    

    ​ XML:

    <server>
    	<port>8081</port>
    </server>
    

    2、YAML基本语法

    1.基本语法

    K:(空格)v ---->表示一个键值对

    以空格控制缩进来控制层级关系,左对齐的配置都是同一层级

    server:
      port: 8081
      path: /hello
    

    属性和值都是大小写敏感的

    2.值的写法
    • 字面量:普通的值(数字、字符串、布尔值)

      • 字符串默认不加单双引号

      • " ":会转义字符串里面的特殊字符

        • name:"wiggin list " ==> 输出:wiggin "换行" list
      • ' ':不会转移字符串里面的特殊字符

        • name:‘wiggin list ’ ==> 输出:wiggin list
    • 对象、map(属性和值)(键值对)

      • k: v:

        • 对象还是k: v方式:

          friends:
            name: wiggin
            age: 18
          
        • 行内写法:

          friend: {name: wiggin,age: 18}
          
    • 数组(List、set)

      用- 值表示数组中的一个元素

      • k: v方式:

        pets:
        - cat
        - dog
        
      • 行内写法

        pet: {cat,dog}
        
    3.配置文件值注入
    • 配置文件

      # application.yml
      person:
        name: wiggin
        age: 18
        boss: false
        birth: 2019/12/18
        map: {k1: v1,k2: 12}
        list:
          - vivid
          - tom
        dog:
          name: golf
          age: 18
      
      #application.propertis
      
      # idea配置文件propertis用的utf-8编码需要对中文进行编码转换
      
      person.name=张三
      person.age=18
      person.boss=false
      person.birth=2018/12/18
      person.map.k1=v1
      person.map.k2=v2
      person.list=a,b,c
      person.dog.name=dog
      person.dog.age=15
      

      注意:idea配置文件propertis用的utf-8编码需要对中文进行编码转换在file-setting-editor-fileecoding勾选

    • javaBean:

      /*
      * 将配置文件中每个属性的值,映射到这个组件中
      * @ConfigurationProperties:告诉Spring Boot将本类中的所有属性和配置文件中相关联的配置进行绑定
      *       prefix = "person",指定配置文件中的属性进行映射
      * 只有这个组件时容器中的组件,才能容器中提供@ConfigurationProperties功能
      * */
      @Component
      @ConfigurationProperties(prefix = "person")
      
      public class Person {
          private String name;
          private Integer age;
          private Boolean boss;
          private Date birth;
      
          private Map<String,Object> map;
          private List<Object> list;
          private Dog dog;
          }
      
    • 导入配置文件处理器的依赖

      <!--        导入配置文件处理器,配置文件进行绑定就会有提示 -->
            <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-configuration-processor</artifactId>
                  <optional>true</optional>
                  <version>2.3.4.RELEASE</version>
              </dependency>
      
    4.@ConfigurationProperties与@Value的比较

    对于spring里面的bean是这样定义的

     <bean class="Person">
             <property name="name" value="?"></property>
     </bean>
    

    其中value的值有三种形式:

    • 字面量

    • ${key}从环境变量、配置文件中获取值

    • {Spel}Spel为spring表达式语言

    在spring Boot中的可以用@Value来替换@ConfigurationProperties注解

    @Component
    //@ConfigurationProperties(prefix = "person")
    public class Person {
        /*
        * <bean class="Person">
             <property name="name" value="?"></property>
            </bean>
        * */
        @Value("${person.name}")
        private String name;
        @Value("#{11*2}")
        private Integer age;
        @Value("true")
        private Boolean boss;
        private Date birth;
    
    

    @Value和@ConfigurationProperties获取值的比较

    @ConfigurationProperties @Value
    功能 批量注入文件中的而属性 逐个指定
    松散绑定 对于属性驼峰命名和用”-“连接的意义相同 不支持
    SpEL 不支持 支持
    JSR303数据校验 支持 不支持
    复杂类型封装(map) 支持 不支持
    @Component
    @ConfigurationProperties(prefix = "person")
    @Validated
    public class Person {
        @Email
        private String name;
    
        private Integer age;
    

    报错-------》Reason: 不是一个合法的电子邮件地址

    总结:如果说在某个业务逻辑中需要获取以下配置文件的某项值,使用@Value;如果专门编写了javabean和配置文件进行映射,就直接使用@ConfigurationProperties

    5.@PropertySource和@ImportResource
    @Component
    @ConfigurationProperties(prefix = "person")
    @PropertySource(value = {"classpath:person.properties"})
    @Validated
    public class Person {  
        private String name;
        private Integer age;
        private Boolean boss;
        private Date birth;
    

    @PropertySource:导入SpringBoot的配置文件,让配置文件的内容生效,不在使用全局配置文件application.yml,而是用自定义的配置文件person.properties

    注意:@ConfigurationProperties()和@PropertySource()连用才能生效.

    @ImportResource:导入Spring的配置文件,让配置内容生效;但是SpringBoot中没有Spring的配置文件,自定义的bean.xml文件不能生效。可以通过在启动类上标注@ImportResource来使自定义bean.xml生效

    • 测试应用

      /*
      * Spring Boot单元测试:
      * 可以在测试期间类似编码一样进行自动注入的容器的功能
      * */
      @RunWith(SpringRunner.class)
      @SpringBootTest
      class SpringBoot02ConfigApplicationTests {
          @Autowired
          Person person;   
          // 定义一个ioc实例
          @Autowired
          ApplicationContext ioc;
          @Test
          public void testHelloService(){
              // 判断bean中是否有helloService
              boolean b = ioc.containsBean("helloService");
              System.out.println(b);
          }
          @Test
          void contextLoads() {
              System.out.println(person);
          }
      
      }
      
      
    • 启动应用

      package com.wiggin.springboot;
      
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.context.annotation.ImportResource;
      
      // 导入Spring配置文件让它生效
      @ImportResource(locations = {"classpath:beans.xml"})
      @SpringBootApplication
      public class SpringBoot02ConfigApplication {
      
          public static void main(String[] args) {
              SpringApplication.run(SpringBoot02ConfigApplication.class, args);
          }
      
      }
      
      
    • bean.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <bean id="helloService" class="com.wiggin.springboot.service.HelloService" ></bean>
      </beans>
      

    但是SpringBoot推荐给容器中添加组件的方式,推荐使用全注解的方式:

    • 配置类代替Spring配置文件(和@Value一样,用@Bean注解来注入)

      /*
      * @Configurable指明当前类使一个配置类,就是来替代之前的spring配置文件
      *
      * */
      @Configuration
      public class MyAppConfig {
          // 将方法的返回值添加到容器中,容器中组件的默认的id就是方法名
          @Bean
          public HelloService helloService(){
              System.out.println("配置类@bean给容器添加组件了");
              return new HelloService();
          }
      }
      
      
    6.配置文件的占位符
    • 随机数

      person.age=${random.int}
      
    • 占位符想要取已经设定的值,如果没有可以指定默认值

      person.dog.name=${person.hello:hello}_dog
      
    7.Profile
    • 多Profile文件

      我们在主配置文件编写的时候,文件名可以使application-{profile}.properties/yml

      默认使用的application.properties

    • 激活指定的profile

      • 在配置文件中指定激活的配置:spring.profiles.active=dev

      • 命令行方式激活:--spring.profile.active=dev,但优先使用的application.properties文件里的配置

        也可在打包后运行jar包时候加入--spring.profile.active=dev

      • 虚拟机参数:-Dspring.profiles.active=dev

    • yml支持多文档块

      server:
        port: 8082
      spring:
        profiles:
          active: prod
      ---
      server:
        port: 8083
      spring:
        profiles: dev
      ---
      server:
        port: 8084
      spring:
        profiles: prod  # 指定环境
      
    8.配置文件的加载位置

    Spring Boot启动会所有以下位置的application.properties/yml文件作为默认配置,优先级为:

    -file:/config/ -------------------> 根目录下的config文件中的配置文件

    -file:./ -------------------> 根目录下的配置文件

    -classpath:/config/ -------------------> resources下的config文件中的配置文件

    -classpath:/ -------------------> resources目录下的配置文件

    高优先级的配置会覆盖低优先级的配置,会形成互补配置

    在项目打包之后,可以通过使用spring.config.location= 地址,但只能在命令行中实行

    9.外部配置加载顺序
    1. @TestPropertySource 注解
    2. 命令行参数
    3. Java系统属性(System.getProperties())
    4. 操作系统环境变量
    5. 只有在random.*里包含的属性会产生一个RandomValuePropertySource
    6. 在打包的jar外的应用程序配置文件(application.properties,包含YAML和profile变量)
    7. 在打包的jar内的应用程序配置文件(application.properties,包含YAML和profile变量)
    8. 在@Configuration类上的@PropertySource注解
    9. 默认属性(使用SpringApplication.setDefaultProperties指定)

    3、自动配置的原理

    配置文件配置的属性:配置属性文档

    1.自动配置原理:

    1)springBoot启动的时候加载主配置类,开启自动配置功能@EnableAutoConfiguration

    1. @EnableAutoConfiguration的作用:

       		- 利用AutoConfigurationImportSelector.class给容器中导入一些组件?
      
      • 可以查看selectImports方法里面的内容。

      • List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
        

        在getCandidateConfigurations中有个SpringFactoriesLoader方法,SpringFactoriesLoader调用SpringFactoriesLoader方法,

        //通过上面的方法加载spring.factories里面的信息,转化为url格式
        Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                         
        while(urls.hasMoreElements()) {
            URL url = (URL)urls.nextElement();
            UrlResource resource = new UrlResource(url);
            // 将url内容包装成properties对象
            Properties properties = PropertiesLoaderUtils.loadProperties(resource);	      		
            Iterator var6 = properties.entrySet().iterator();
            // 遍历每个properties获取其中的值
            while(var6.hasNext()) {
             Entry<?, ?> entry = (Entry)var6.next();
             String factoryTypeName = ((String)entry.getKey()).trim();
             String[] var9 =           	StringUtils.commaDelimitedListToStringArray((String)entry.getValue());        
             int var10 = var9.length;
        
              for(int var11 = 0; var11 < var10; ++var11) {
                     String factoryImplementationName = var9[var11];
                     result.add(factoryTypeName, factoryImplementationName.trim());
                                }
                            }
        

        将类路径下的META-INF/spring.factories里面的配置的的所有EnableAutoConfiguration 的值加入容器中

        # Auto Configure
        org.springframework.boot.autoconfigure.EnableAutoConfiguration=
        org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
        org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,
        org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,
        org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,
        org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,
        ........
        

        每一个这样的xxxAutoConfiguration类都是容器中的一个组件,都加入到容器当中,让他们自动配置

        3)每一个配置类进行自动配置功能;

        4)以HttpEncodingAutoConfiguration(Http编码自动配置)为例解释自动配置功能

        // 说明这是一个配置类
        @Configuration(proxyBeanMethods = false)
        
        // 启用指定类的ConfigurationProperties功能,将ServerProperties中的配置与HttpEncodingAutoConfiguration绑定起来,并把下面的properties加入到ioc容器中
        @EnableConfigurationProperties({ServerProperties.class})
        
        // Spring底层有个@Conditional注解,根据不同条件,如果满足条件,整个配置类的配置就会生效,判断当前应用是否使web应用
        @ConditionalOnWebApplication(type = Type.SERVLET)
        
        // 判断当前项目有没有这个类,CharacterEncodingFilter是解决乱码的过滤器
        @ConditionalOnClass({CharacterEncodingFilter.class})
        
        // 判断配置文件中是否存在配置server.servlet.encoding为enabled,如果matchIfMissing也是生效的
        @ConditionalOnProperty(
            prefix = "server.servlet.encoding",
            value = {"enabled,如果"},
            matchIfMissing = true
        )
        public class HttpEncodingAutoConfiguration {
            // 它已经和spring Boot中的配置文件映射了,可以在application.yml中重新配置
            private final Encoding properties;
        	
            // 只有一个有参构造器的情况下,参数的值就会从容器中拿到
            public HttpEncodingAutoConfiguration(ServerProperties properties) {
                this.properties = properties.getServlet().getEncoding();
            }
        
            @Bean // 给容器中添加组件,这个组件的某些属性需要从properties中获取
            @ConditionalOnMissingBean //没有这个bean才加入功能
            public CharacterEncodingFilter characterEncodingFilter() {
                CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
                filter.setEncoding(this.properties.getCharset().name());      filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));      filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));
                return filter;
            }
        
        

        根据当前的不同条件判断,决定这个配置类是否生效

        一旦这个配置类生效,这个配置类就会给容器中添加各种组件;这些组件的属性是从对应的properties中获取的,properties的属性又和配置文件绑定

        5)所有在配置文件中能配置的属性都在xxxproperties类中分装着,配置文件能配置什么就可以参照每一个功能对应的属性类

        @ConfigurationProperties(
            prefix = "server",
            ignoreUnknownFields = true
        )// 从配置文件中获取指定的值和Bean的属性进行绑定
        public class ServerProperties {
            private Integer port;
            private InetAddress address;
           
        

    Spring Boot的精髓

    1)Spring Boot启动会加载大量的自动配置类

    2)寻找需求功能的自动配置类

    3)查看配置类中的组件(如果包含完成需求功能的组件,就不需要自定义配置类)

    4)从容器中自动配置类添加组件的时候,会从properties类中获取某些属性,这些属性可以在指定的配置文件进行赋值

    xxxAutoConfiguration:自动配置类,给容器中添加组件

    xxxProperties:封装配置文件中的相关属性与默认值

    细节

    1.@Conditional

    作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置类里面的内容才会生效

    @Conditional扩展注解 作用(判断是否满足当前指定条件)
    @ConditionalOnJava 系统的java版本是否符合要求
    @ConditionalOnBean 容器中存在指定Bean;
    @ConditionalOnMissingBean 容器中不存在指定Bean;
    @ConditionalOnExpression 满足SpEL表达式指定
    @ConditionalOnClass 系统中有指定的类
    @ConditionalOnMissingClass 系统中没有指定的类
    @ConditionalOnSingleCandidate 容器中只有一个指定的Bean,或者这个Bean是首选Bean
    @ConditionalOnProperty 系统中指定的属性是否有指定的值
    @ConditionalOnResource 类路径下是否存在指定资源文件
    @ConditionalOnWebApplication 当前是web环境
    @ConditionalOnNotWebApplication 当前不是web环境
    @ConditionalOnJndi JNDI存在指定项

    自动配置类大多需要一定的条件才能生效

    如何知道哪些自动配置类的生效?

    可以在application.properties启用debug=true的方式,让控制台打印自动报告,了解生效的自动配置有哪些,哪些没有生效,需要继续配置。

    Positive matches:
    -----------------
    
       AopAutoConfiguration matched:
          - @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)
    
       AopAutoConfiguration.ClassProxyingConfiguration matched:
          - @ConditionalOnMissingClass did not find unwanted class 'org.aspectj.weaver.Advice' (OnClassCondition)
          - @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition)
    
    
    Negative matches:
    -----------------
    
       ActiveMQAutoConfiguration:
          Did not match:
             - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
    
  • 相关阅读:
    makedown
    前端
    关于阅读与自我认同
    Win10任务栏透明工具 TranslucentTB
    Linux文件属性
    解决vscode出现两个光标的问题
    一文搞懂vim复制粘贴
    解决vim选中文字不能复制的问题
    简单配置让iterm2用得更爽
    区块链相关在线加解密工具(非对称加密/hash)
  • 原文地址:https://www.cnblogs.com/wigginess/p/13938932.html
Copyright © 2011-2022 走看看