美文网首页
SpringBoot教程(三)(配置文件解析)_下

SpringBoot教程(三)(配置文件解析)_下

作者: 文思li | 来源:发表于2018-07-24 22:03 被阅读0次

          配置文件解析(下)

                                                                                                     原创者:文思

    一、yml(YAML Ain’t Markup Language)基本用法

    application.properties或application.yml

    配置文件的作用:修改springboot的默认配置。

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

    基本语法:

    K:(空格)V :表示一对键值对。以空格的缩进来控制层级关系,只要是左对齐的一列数据,都是一个层级的。

    值的写法:

    字面量:普通的值(数据、字符串、布尔),k: v形式直接来写。如果有特殊字符,不需要转义可用双引号,需要转义可用单引号。

    对象、Map:k: v形式直接来写,在下一行写对象的属性和值,注意缩进。

    还可以使用行内写法:friends:{name:zhangsan,age: 18}

    数组(List、Set):用- 值表示数组中的一个元素

    示例:

    新建一个yml配置文件:

    server:

         port: 8081

    person:

         lastName: zhangsan

         age: 18

         boss:  false

         birth:  2018/7/17

     map:  {t1:test1,t2:test2,t3:test3}

     map2:

       t1:  test11

       t2:  test22

       t3:  test33

    list:

       -  lisi

       -  wangwu

       -  zhaoliu

     dog:

        name:  小狗

        age:  2

    创建对应的对象:

    @Component//声明为spring组件,让spring容器管理

    @ConfigurationProperties(prefix="person")//默认从全局配置文件中获取值,告诉springboot将此类的属性与配置文件的配置绑定

    public classPerson {

        private String lastName;

        private Integer age;

        private Boolean boss;

        private Date birth;

        privateMap map;

        privateMap map2;

        private List list;

        private Dog dog;

        public String toString(){

           return "Person{"+

                  "lastName="+ lastName+

                  ",age="+ age+

                  ",boss="+ boss+

                  ",birth="+ birth+

                  ",map="+ map+

                  ",map2="+ map2+

                  ",list="+ list+

                  ",dog="+ dog+

                  "}";

        }

     .....setter\getter方法略

    }

    package com.wensi.springbootdemo1.yml;

    public classDog {

        private String name;

        private Integer age;

        public String getName() {

           return name;

        }

     .....setter\getter方法略

    }

    运行测试类:

    package com.wensi.springbootdemo1;

    import org.junit.Test;

    import org.junit.runner.RunWith;

    import org.springframework.beans.factory.annotation.Autowired;

    import org.springframework.boot.test.context.SpringBootTest;

    import org.springframework.test.context.junit4.SpringRunner;

    import com.wensi.springbootdemo1.yml.Person;

    @RunWith(SpringRunner.class)

    @SpringBootTest

    public classAppTest{

        @Autowired

        Personperson;

        @Test

        public void contextLoads(){

           System.out.println(person);

        }

    }

    运行结果:

    Person{lastName=zhangsan,age=18,boss=false,birth=Tue Jul 17 00:00:00 CST 2018,map={t1=test1, t2=test2, t3=test3},map2={t1=test11,t2=test22, t3=test33},list=[lisi, wangwu,zhaoliu],dog=com.wensi.springbootdemo1.yml.Dog@796d3c9f}

    使用properties格式的配置文件application.properties:

    person.lastName=zhangsan

    person.age=18

    person.boss=false

    person.birth=2018/7/17

    person.map.t1=test1

    person.map.t2=test2

    person.map.t3=test3

    person.list=lisi,wangwu,zhaoliu

    person.dog.name=小狗

    person.dog.age=2

    运行测试类的结果:

    Person{lastName=zhangsan,age=18,boss=false,birth=TueJul 17 00:00:00 CST 2018,map={t3=test3, t2=test2,t1=test1},map2=null,list=[lisi, wangwu,zhaoliu],dog=com.wensi.springbootdemo1.yml.Dog@6f8d7714}

    使用@value:

    @Component

    public class PersonValue {

        @Value("${person.lastName}")

        private String lastName;

        @Value("#{2*11}")

        private Integer age;

        @Value("true")

        privateBooleanboss;

    运行结果:

    Person{lastName=zhangsan,age=22,boss=true,birth=null,map=null,map2=null,list=null,dog=null}

    @value和@ConfigurationProperties区别:

    例如:

    @Component

    @ConfigurationProperties(prefix="person")

    @Validated

    public class Person {

        @Email

        private String lastName;//lastName必须是邮箱格式

        private Integer age;

        private Boolean boss;

        private Date birth;

    运行结果:

    Binding to targetPerson{lastName=zhangsan,age=18,boss=false,birth=Tue Jul 17 00:00:00 CST2018,map={t3=test3, t2=test2, t1=test1},map2=null,list=[lisi, wangwu,zhaoliu],dog=com.wensi.springbootdemo1.yml.Dog@7689ddef} failed:

        Property:person.lastName

        Value:zhangsan

        Reason: 不是一个合法的电子邮件地址

    使用@value时:

    @Component

    @Validated

    public class PersonValue {

        @Email

        @Value("${person.lastName}")

        private String lastName;

    运行结果:

    Person{lastName=zhangsan,age=22,boss=true,birth=null,map=null,map2=null,list=null,dog=null}。说明@value不支持数据校验

    对于复杂数据类型:

    @Component

    public class PersonValue {

        @Value("${person.lastName}")

        private String lastName;

        @Value("#{2*11}")

        private Integer age;

        @Value("true")

        private Boolean boss;

        private Date birth;

        @Value("${person.map}")

        private Map map;

    运行结果:

    Caused by: java.lang.IllegalArgumentException:Could not resolve placeholder 'person.map' in value "${person.map}"

    说明@value不支持复杂数据类型,如map。

    使用建议:

    如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value。

    如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties

    @PropertySource和@importResource

    根据名称分析@PropertySource可加载非默认的配置文件,即加载指定的配置文件,当我们想将一些特定业务所需要的配置与系统默认配置分开维护时,需要@PropertySource

    @Component

    @ConfigurationProperties(prefix="person")

    @PropertySource(value={"classpath:person.properties"})

    public class PersonPropertySource {

        private String lastName;

        privateInteger age;

    运行结果:

    Person{lastName=zhangsan,age=18,boss=false,birth=Tue Jul 17 00:00:00 CST 2018,map={t3=test3, t2=test2,

    t1=test1},map2=null,list=[lisi, wangwu,zhaoliu],dog=com.wensi.springbootdemo1.yml.Dog@1b32cd16}

    @importResource导入spring的配置文件,让配置文件里面的内容生效

    因为springboot里面没有spring的配置文件,自己编写地配置文件也不能识别,所以需要使用@importResource加载进来。示例:

    public class TestImportService {

    }

    bean.xml:

    @SpringBootApplication

    @ImportResource(locations = {"classpath:bean.xml"})

    public class App

    {

    ……

    }

    测试用例:

    @Autowired

        ApplicationContext ioc;

        @Test

        public void testImportSource(){

           System.out.println(ioc.containsBean("testImportService"));

        }

    运行结果:true

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

    1、配置类@Configuration------>Spring配置文件

    2、使用@Bean给容器中添加组件,配置类这里使用@Bean注解

    /**

    * @Configuration:指明当前类是一个配置类;就是来替代之前的Spring配置文件

    ** 在配置文件中用标签添加组件

    */

    @Configuration

    public class MyAppConfig {

    //将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名

            @Bean

            public HelloService helloService02(){

                System.out.println("配置类@Bean给容器中添加组件了...");

                return new HelloService();

            }

    }

    配置文件占位符

    1、随机数:

    ${random.value}、${random.int}、${random.long}

    ${random.int(10)}、${random.int[1024,65536]}

    2、占位符获取之前配置的值,如果没有可以是用:指定默认值

    person.last‐name=张三${random.uuid}

    person.age=${random.int}

    person.birth=2017/12/15

    person.boss=false

    person.maps.k1=v1

    person.maps.k2=14

    person.lists=a,b,c

    person.dog.age=15

    person.dog.name=${person.hello:hello}_dog 

    如果${person.hello: hello}取不到值就默认值hello

    多profile文件

    应该对开发\测试\生产环境下切换

    文件名可以是application-{profile}.properties/yml

    默认使用的是application.properties/yml

    激活指定profile

    在配置文件中指定spring.profile.activie=dev,示例,新建application-dev.properties:

    application.properties中增加spring.profile.activie=dev

    Yml格式的多profile:yml支持文档块模式

    spring:

      profiles:

        active: prod

    ---

    server:

      port: 8083

    spring:

      profiles: prod

    ---

    server:

      port: 8084

    spring:

      profiles:dev

    运行如图:

    spring.profiles.active是激活使用指定的配置文件。

    另一种可以使用命令行的方式:java -jar ***.jar –spring.profiles.active=dev

    还有一种虚拟机参数:-Dspring.profiles.active=dev

    配置文件加载位置

    Spring

    boot启动会扫描以下位置的application.properties或yml作为spring

    boot的默认配置文件

    -file:./config/

    -file:./

    -classpath:/config/

    -classpath:/

    以上是按照优先级从高到低的顺序,所有位置的文件都会被加载,高优先级配置内容会覆盖低优先级配置内容。

    外部配置加载顺序

    SpringBoot也可以从外部以下位置加载配置; 优先级从高到低;高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置

    1.命令行参数

    所有的配置都可以在命令行上进行指定

    java -jarspring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087--server.context-path=/abc

    多个配置用空格分开;--配置项=值

    2.来自java:comp/env的JNDI属性

    3.Java系统属性(System.getProperties())

    4.操作系统环境变量

    5.RandomValuePropertySource配置的random.*属性值由jar包外向jar包内进行寻找;优先加载带profile

    6.jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件

    7.jar包内部的application-{profile}.properties或application.yml(spring.profile)配置文件再来加载不带profile

    8.jar包外部的application.properties或application.yml(不spring.profile)配置文件

    9.jar包内部的application.properties或application.yml(不spring.profile)配置文件

    10.@Configuration注解类上的@PropertySource

    11.通过SpringApplication.setDefaultProperties指定的默认属性

    示例:

    java

    -jar springbootdemo1-0.0.1-SNAPSHOT.jar -server.port=8088,

    启动端口就覆盖配置文件的里的端口设置了,启动端口为8088

    二、自动配置原理

    配置文件能配置的属性参照:

    https://docs.spring.io/spring-boot/docs/1.5.9.RELEASE/reference/htmlsingle/#common-application-properties

    观察@ SpringBootApplication源码

    @Target(ElementType.TYPE)

    @Retention(RetentionPolicy.RUNTIME)

    @Documented

    @Inherited

    @SpringBootConfiguration

    @EnableAutoConfiguration

    @ComponentScan(excludeFilters = {

           @Filter(type = FilterType.CUSTOM, classes =

    TypeExcludeFilter.class),

           @Filter(type = FilterType.CUSTOM, classes =

    AutoConfigurationExcludeFilter.class) })

    public @interface SpringBootApplication

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

    2) @EnableAutoConfiguration利用EnableAutoConfigurationImportSelector选择器给容器导入META-INF/Spring.factories中的默认配置对应的组件。(可查看selectImports()方法-->

    List configurations = getCandidateConfigurations(annotationMetadata, attributes);获取候选的配置-->

    SpringFactoriesLoader.loadFactoryNames()//扫描所有jar包类路径下META‐INF/spring.factories把扫描到的这些文件的内容包装成properties对象从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中)

    3)如上每一个自动配置类进行自动配置

    4) 以HttpEncodingAutoConfiguration(Http编码自动配置)为例解释自动配置原理;

    @Configuration //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件

    @EnableConfigurationProperties(HttpEncodingProperties.class)

    //启动指定类的

    ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把

    HttpEncodingProperties加入到ioc容器中

    @ConditionalOnWebApplication

    //Spring底层@Conditional注解(Spring注解版),根据不同的条件,如果

    满足指定的条件,整个配置类里面的配置就会生效; 判断当前应用是否是web应用,如果是,当前配置类生效

    @ConditionalOnClass(CharacterEncodingFilter.class)

    //判断当前项目有没有这个类

    CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;

    @ConditionalOnProperty(prefix= "spring.http.encoding", value = "enabled", matchIfMissing=

    true) //判断配置文件中是否存在某个配置spring.http.encoding.enabled;如果不存在,判断也是成立的

    //即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;

    public class HttpEncodingAutoConfiguration{

    //他已经和SpringBoot的配置文件映射了

    private final HttpEncodingPropertiesproperties;

    //只有一个有参构造器的情况下,参数的值就会从容器中拿

    publicHttpEncodingAutoConfiguration(HttpEncodingProperties properties) {

    this.properties =properties;

    }

    @Bean //给容器中添加一个组件,这个组件的某些值需要从properties中获取

    @ConditionalOnMissingBean(CharacterEncodingFilter.class)

    //判断容器没有这个组件?

    publicCharacterEncodingFilter characterEncodingFilter() {

    CharacterEncodingFilter filter = newOrderedCharacterEncodingFilter();

    filter.setEncoding(this.properties.getCharset().name());

    filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));

    filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));

    return filter;

    }

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

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

    这里能看出配置文件能配置的属性都是来源于HttpEncodingProperties类。

    精髓:

    1:spring boot启动会加载大量的自动配置类

    2:我们看我们需要的功能有没有springboot默写好的自动配置类

    3:我们看这个自动配置类中配置了哪些组件(我们要用的有就不用再配置了)

    4:给容器中自动配置类添加组件时,会从properties类中获取某些属性,我们可以在配置文件中指定这些属性的值

    xxxAutoConfigurartion自动配置类,给容器中添加组件,xxxAutoConfigurartion下的xxxxProperties:封装配置文件中相关属性;

    相关文章

      网友评论

          本文标题:SpringBoot教程(三)(配置文件解析)_下

          本文链接:https://www.haomeiwen.com/subject/pmzymftx.html