2020:day0625---SpringBoot配置

409 阅读8分钟

今日内容

1.配置文件
2.加载顺序
3.配置原理

1.配置文件

    1.配置文件
        SpringBoot使用一个全局的配置文件:名字固定
        * application.properties
        * application.yml
        
        配置文件放在:src/main/resources目录或者在:类路径/config
        
        这两个文件SpringBoot都会把它当成全局配置文件。
    
    2.配置文件的作用
        由于SpringBoot在地层默认给我们配置好了,全局配置文件可以对一
    些默认配置进行修改。
    
    3. application.yml
    
        1.yml是YAML(YAML Ain't Markup Language)语言的文件,以数据为
    中心,比json,xml等更适合做配置文件
        
        2.标记语言:Markup Language
            以前的配置文件,大多使用的是xxx.XML文件
            
        3.yml:配置端口 以数据为中心
                server:
                  port: 8089
       4.XML:配置端口
                <server>
                    <port>8089</port>
                </server>

2. YAML语法

    1. YAML基本语法:怎么表示属性和值的关系
        K: V表示一对键值对(空格必须有);
        
        以空格的缩进来控制层级关系:只要是左对齐的一列数据都是同一层级的;
        在yml文件中,不可以使用“tab”键来缩进!缩进要使用空格来缩进;
        
        属性和值也是大小写敏感的。
            server:
                port: 8089
                path: /hello
    2. 值的写法
        1.字面量:普通的值(数字,字符串,布尔)
            K: v 字面量直接来写:
                字符串默认不用加上单引号或者双引号。
                "":双引号,不会转义字符串里面的特殊字符;特殊字符会
                    作为本身想表达的意思。
                    
                    例如:特殊字符作为特殊字符想表达的意思
                        name: "zhangsan\n lisi"
                        输出:zhangsan (换行)
                              lisi
                    例如:会转义特殊字符,特殊字符最终只是一个普通的字符串数据。    
                        name: 'zhangsan\n lisi'
                        输出: zhangsan\n lisi
        
        2.对象,Map:属性和值(键值对)
            
            K: V :对象还是K: V的方式
                值是对象的时候,第一行对象,下一行对象的属性和值(注意缩进)。
                
                friends:
                    lastName: zhangsan
                    age: 20
                    
            对象的行内写法:
                friends: {lastName: zhangsan,age: 18}
        
                    
            
        3.数组(List,Set):用-值表示数组中的一个元素
        
                pets:
                  - cat
                  - dag
                  - pig
          数组的行内写法:
            pets: [cat,dog,pig]

3.将application.yml中配置属性值注入到Bean中

3.1

    1.application.yml配置文件:
        person:
          lastName: zhangsan
          age: 18
          boss: false
          birth: 2019/12/12
          maps: {k1: v1, k2: 12}
          list:
            - lisi
            - zhaoliu
            - zhangsan
          dog:
            name: 小狗
            age: 2
    2.实体类
            @Component
            @ConfigurationProperties(prefix = "person")
            public class Person {
            
                private String name;
                private Integer age;
                private Boolean boss;
                private Date birth;
            
                private Map<String,Object> maps;
                private List<Object> list;
                private Dog dog;
            
                public String getName() {
                    return name;
                }
            }
        注意1:@ConfigurationProperties(prefix = "person")
            要导入一个SpringBoot配置文件的处理器的依赖。
        <!--导入配置文件处理器,配置文件进行绑定就会有提示-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        注意2:@Component
            要想该实体类能起作用,那么必须是Spring容器中的组件,只有
        这个组件是容器中的组件,才能使用容器提供的功能。
    
    3. 测试类:
        引导器创建的SpringBoot项目会自动生层一个测试类
        
        @SpringBootTest : 说明是一个SpringBoot的单元测试
        @RunWith(SpringRunner.class) : 
            单元测试用SpringBoot的驱动器。此版本该注解可能集成在别处了。
            可以在测试期间很方便的进行自动注入的功能
    @SpringBootTest
    class Day0625SpringBoot01ConfigApplicationTests {
    
        @Autowired
        Person person;
    
        @Test
        void contextLoads() {
            System.out.println(person);
        }
    }

3.2 配置application.properties

        person.name=张三
        person.age=15
        person.birth=2019/12/01
        person.boss=false
        person.maps.k1=v1
        person.maps.k2=14
        person.list=a,b,c
        person.dog.name=dog
        person.dog.age=15

    测试时,张三会乱码
    
    解决:

3.3 用@Value注解为单个属性注入

    1. 我们以前在配置文件中向IOC容器注入时
<bean class="Person">
    <properties name="lastname" value=""/>
</bean>
 
    其中<bean/>是将实体类Person扫描进去
    name="lastname"为Person对象中的lastname属性赋值
    value="":赋具体的值
        有三种写法:
        1.valeu="字面量"
            @Value("true")
            private Boolean boss;
            
        2.value="${key}": 从环境变量,配置文件中获取值
            @Value("${person.lastname}")
            private String lastname;
            
        3.value="#{SpeL语言}"
            @Value("#{11*2}")
            private Integer age;
        

    2. 实体类Person
        @Component
        //@ConfigurationProperties(prefix = "person")
        public class Person {
            @Value("${person.lastname}")
            private String lastname;
            @Value("#{11*2}")
            private Integer age;
            @Value("true")
            private Boolean boss;
            private Date birth;
        
            private Map<String,Object> maps;
            private List<Object> list;
            private Dog dog;
        }
    其中@Component就类似<bean/>标签,向IOC注入Person对象
    @Value:为单个属性注入
        @Value("${person.lastname}")
        private String lastname;
        @Value("#{11*2}")
        private Integer age;
        @Value("true")
        private Boolean boss;
        
        
    3. 同@ConfigurationProperties的区别:
            1.功能
                @ConfigurationProperties只需要一个注解,可以为我们批量注入属性。
                @Value:只能为单个属性注入。
            
            2. 松散语法
                @ConfigurationProperties支持松散于法绑定
                    Person:
                        private String lastName;
                    application.yml:
                        person:
                          last-name: 张三
                    
                    松散绑定将last-name注入到lastName上。
            
            3. 支持SPEL
                @ConfigurationProperties不支持
                @Value支持
                
            4. JSR303数据校验:
                @ConfigurationProperties支持
                我们在为属性注入值时,能够校验一下。

                如果不满足校验规则,会报错。
                
                @Value不支持 
                即使在为属性注入时,加入验证也不会生效,所以不会报错。

            注意:在使用JSR303数据校验时,要导入一个新的依赖
                6.0.0.Alpha5 版本很大
                <dependency>
                    <groupId>org.hibernate</groupId>
                    <artifactId>hibernate-validator</artifactId>
                    <version>6.0.0.Final</version>
                </dependency>
            5. 复杂类型属性注入时:
                 @ConfigurationProperties支持
                 @Value不支持

        区别小结:
            如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的
        某项值,可以用@Value
            @RestController
            public class HelloController {
            
                @Value("${person.lastname}")
                private String name;
            
                @RequestMapping("/sayHello")
                public String sayHello(){
                    return "hello" + name;
                }
            }
            如果说,专门编写了一个javaBean来和配置文件进行映射,我们
        就直接使用@ConfigurationProperties。

4.@Property和@ImportResource

4.1 @ConfigurationProperties结合@PropertySource读取指定配置文件

    我们知道@ConfigurationProperties能将实体类和配置文件中的值进行绑定。
但是绑定的前提是要求你的属性都写在了application.properties/yml中。
    即@ConfigurationProperties默认是从全局配置文件中获取值。
        application.properties
        application.yml
   
    显然我们不可能将所有的配置都放到一个全局配置文件中,那么一些和SpringBoot
无关的配置,我们就希望放到别的配置文件中。

    1.将原来在全局配置中的person.xxx放到person.properties中
      将全局配置中的person.xxx注释
            person.lastname=李四
            person.age=15
            person.birth=2019/12/01
            person.boss=false
            person.maps.k1=v1
            person.maps.k2=14
            person.list=a,b,c
            person.dog.name=dog
            person.dog.age=15
    2. @ConfigurationProperties(prefix = "person")
        那么该注解:从全局配置中去前缀是person的值,显然取不到了。
        
    3. 结合@PropertySource:加载指定的配置文件
    
       @PropertySource(value = {"classpath:person.properties"}) 
       告诉SpringBoot来加载类路径下的person.properties的内容,并把它们绑定到
       javaBean的属性中。
        @Component
        @PropertySource(value = {"classpath:person.properties"})
        @ConfigurationProperties(prefix = "person")
        public class Person {
            private String lastname;
            private Integer age;
            private Boolean boss;
            private Date birth;
        }

4.2 @ImportResource

    我们自己编写的配置文件,SpringBoot不会自动解析。
    @ImportResource导入Spring的配置文件,让配置文件里面的内容生效
    
    1.写了个spring配置文件: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.atguigu.day0625_springboot.service.HelloService"></bean>
</beans>
    在里面写了一个<bean/>配置,此时bean.xml没有被解析,所以IOC容器中没有这个bean。
    
    2.测试一下
        @Autowired
        ApplicationContext ioc;
    
        @Test
        public void testHelloService(){
            boolean flag = ioc.containsBean("helloService");
            System.out.println(flag);
        }
    打印结果:false。
    
   3. @ImportResource标注在一个配置类上
    
    我们将其标注在主配置类上:
        @ImportResource(locations = {"classpath:beans.xml"})
        @SpringBootApplication
        public class SpringBoot01ConfigApplication {
        
            public static void main(String[] args) {
                SpringApplication.run(SpringBoot01ConfigApplication.class, args);
            }
        
        }
    导入beans.xml配置文件让其生效。

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

    一般不推荐使用@ImportResource注解给IOC容器添加组件。
        
    1.写一个配置类
        
        可以在主配置类中写,这里我们专门写一个配置类。
            @Configuration
            public class MyConfig {
                //将方法的返回值添加到容器中:容器中这个组件默认的ID就是方法名
                @Bean
                public HelloService helloService(){
            
                    System.out.println("配置类给容器添加组件了");
                    return new HelloService();
                }
            }
        其中:
            @Configuration:指明这是一个配置类
            @Bean:将方法的返回值添加到容器中:容器中这个组件默认的ID就是方法名
    
    2. 不用再加载指定的配置类了,我们测试一下

5 配置占位符

1. 配置文件中可以使用随机数
        person.lastname=张三${random.uuid}
        person.age=${random.int}
        person.birth=2019/12/01
        person.boss=false
        person.maps.k1=v1
        person.maps.k2=14
        person.list=a,b,c
        person.dog.name=${person.lastname}_dog
        person.dog.age=15
2. 测试结果

3. 占位符获取之前配置的值

    如果解析不出来时:当作字符串
    配置文件中没有person.hello所以当成字符串解析。

4. 为person.hello在占位符中指定值
    
    person.dog.name=${person.hello: 小猫}_dog

6 Profile

    Profile是Spring对不同环境提供不同配置功能的支持,可以通过激活指
定参数等方式快速切换环境。

6.1 多Profile文件来实现切换环境

1.  我们在主配置文件编写的时候,文件名可以是:application-{profile}.properties/yml
带上profile标识。
    
    A:当前主配置文件:
    application.propertise:
        server.port=8089
    
    B:比如:我可以再配置两个不同环境的配置文件。
    1.application-dev.properties: 开发环境的配置文件
        server.port=80    
    2.application-prod.properties:  生产环境的配置文件
        server.port=8090
        
2   SpringBoot应用默认使用主配置文件中配置的端口号启动,如何切换到其
他环境,然后使用其他环境中配置的配置文件呢?

    1.激活开发环境的配置:
        在主配置文件中加入如下代码:
        spring.profiles.active=dev
        
        启动应用:切换到开发环境,加载开发环境配置。

6.2 yml支持多文档块的方式:实现切换环境

    我们用yml文件做主配置文件:application.yml
    yml中有一种语法:文档块
    激活方式:
        spring:
          profiles:
            active: dev
            server:
              port: 8089
            
            # 激活开发环境
            spring:
              profiles:
                active: dev

6.3 命令行方式 切换环境

-spring.profiles.active=dev

1.在EidtConfiguration中配置命令行参数

    Program arguments: -spring.profiles.active=dev参数

2.测试:
    主配置文件中激活的是prod环境
    EidtConfiguration中配置的是:dev环境
    
    运行:切换到dev环境

3. 在命令行中 切换环境

    将SpringBoot应用打包
    
    到包所在的目录打开命令行
    
    命令行中运行jar包:
    java -jar day0625_spring-boot01-config-0.0.1-SNAPSHOT.jar
    --spring.profiles.active=dev

    发现也是成功的切换到dev环境中。

4. 虚拟机参数

    VM options:-Dspring.profiles.active=dev

    测试:启动SpringBoot应用

7 配置文件加载优先顺序

    1.
    SpringBoot启动会扫描一下位置的application.properties/yml文件作为
SpringBoot的默认配置文件

    - file:./config
    - file:./               当前项目的根目录下
    - classpath:/config
    - classpath:/

    以上是按照优先级从高到低的顺序,所有位置的文件都会被加载,而且高
优先级配置内容会覆盖低优先级配置内容。
    注意:前提是这些配置文件都是主配置文件:application.properties/yml
    
    2.
    除了主配置文件覆盖的规则外,还有互补配置:
        高优先级的主配置文件,可以覆盖部分内容。其他的配置还用低优先级的配置。
    
        在低优先级的主配置文件中在配置一个项目访问路径:
            server.port=8089
            
            # 配置项目的访问路径:springboot2.x开始
            # server.context-path改成了server.servlet.context-path
            #server.context-path=/boot02
            server.servlet.context-path=/boot02
    结果会将低优先级配置文件中不同于高优先级的内容加载进来。
    
    
    3.
    可以通过配置spring.config.location来改变默认配置。
    
    项目打包好后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件
的新位置。指定配置文件和默认加载的配置文件共同起作用。形成互补配置。
    3.1
    注意:项目打包时,项目根目录下的的文件不会打进去,打包时这些文件不会打进去。

    所以在命令行中启动SpringBoot应用时,优先级最高的是classpath/config
目录下的主配置文件。

    3.2
    在项目外部新建一个主配置文件:application.properties
    
    命令行启动项目,并加载外部的这个配置,会和默认加载的配置文件共同起作用。
java -jar day0625_springboot02_config-0.0.1-SNAPSHOT.jar --spring.config.location=E:\application.properties
    4. 外部配置加载顺序
    
    SpringBoot也可以从以下位置加载配置,优先级从高到低:
    
        1.命令行参数
            在命令行启动SpringBoot应用时,用命令行参数修改默认配置,
        会和默认加载的配置文件共同起作用。
            
            例如:为项目指定一个新的端口和项目路径
java -jar day0625_springboot02_config-0.0.1-SNAPSHOT.jar
--server.port=8087 --server.server.servlet.context-path=/boot02
            多个配置用空格分开:-- 配置项=值
            
            
        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)配置文件

    加载时,jar包外部(同一级目录)的主配置文件不用参数就会自动加载。
    加载顺序如上。

    
        10.@Configuration注解类上的@PropertySource
        11.通过SpringApplication.setDefaultProperties指定的默认属性