美文网首页Spring Boot
Spring Boot 之五:Spring 属性配置

Spring Boot 之五:Spring 属性配置

作者: 小胡_鸭 | 来源:发表于2023-04-05 17:37 被阅读0次

      使用 Spring 为 bean 注入属性时,通常都是在 XML 中设置属性,Java 类的中属性要为其添加 setter 方法,这样在启动的时候才可以去调用。

      比如定义一个 User 类,代码如下:

    package spring.domain;
    
    public class User {
        private String name;
        private int age;
      
        public void setName(String name) {
            this.name = name;
        }
        
        public void setAge(int age) {
            this.age = age;
        }
    }
    

      XML 配置如下:

    <bean id="tom" class="spring.domain.User">
        <property name="name" value="Tom"/> 
        <property name="age" value="20"/>   
    </bean>
    

      在没有显式配置的情况下,为 bean 设置属性并不这么容易。

      而 Spring Bean 提供了配置属性(Configuration Property)的方法。配置属性指为 Spring 上下文中的 Bean 配置属性,属性的数据源可以是 JVM 系统参数、命令行参数和环境变量

    1、细粒度的自动配置

      自动配置的神奇之处在于,我们可以不显式配置 bean(包括 XML 和 Java 配置),比如现在要定义一个嵌入式的 H2 数据源,如果不使用 Spring Boot,则需要定义一个 bean:

    @Bean
    public DataSource dataSource() {
      return new EmbeddedDataSourceBuilder()
            .setType(H2)
            .addScript("schema.sql")
            .addScript("data.sql")
            .build();
    }
    

      而使用 Spring Boot 时,只要引入 H2 的依赖,应用启动运行时就会自动在 Spring 应用上下文中创建对应的 DataSource bean,并且这个 bean 会自动运行名为 schema.sql 和 data.sql 的脚本。

    (1)Spring 环境属性源

      Spring 会拉取多个属性源,包括:

    • JVM 系统属性;
    • 操作系统环境变量;
    • 命令行参数;
    • 应用属性配置文件。

      Spring 会将这些属性聚合到一个源中,通过这个源注入到 Spring Bean,如下图所示:

      Spring Boot 自动配置的 bean 都可以通过 Spring 环境提取的属性进行配置。比如配置应用对外服务端口,可以在 application.properties 中配置:

    server.port=8090
    

      也可以在 application.yml 中配置:

    server:
        port: 8090
    

      如果喜欢在外部配置属性,可以使用命令行参数指定端口:

    $ java -jar springbootapp.jar --server.port=8090
    

      还可以通过环境变量设置:

    $ export SERVER_PORT=8090
    

      Spring 会将 SERVER_PORT 的环境变量解析为 server.port

    (2)配置数据源

      Spring Boot 的自动配置很方便,但是一些属性的值如果跟默认不一致时,我们更希望能够在配置文件中自行配置。

      下面是 H2 数据库的数据源配置:

    # 默认的 H2 数据库名是随机生成的,这里指定为taco,默认用户名为sa,密码为空
    spring:
      datasource:
        url: jdbc:h2:mem:taco
        username: sa
        password:
        
      # 数据初始化
      sql:
        init:
          mode: always
          platform: h2
          username: sa
          password: 
          schema-locations: classpath*:schema.sql
          data-locations: classpath*:data.sql
          
      # h2-console
      #     path: 控制台路径
      #     enabled: 开启Web Console
      #     settings.web-allow-others: 允许远程访问Web Console
      h2:
        console:
          path: /h2-console
          enabled: true
          settings:
            web-allow-others: true
    

      如果有配置跟默认的配置不一致,可以修改响应的属性

      如果要配置 MySQL 的数据源,配置如下:

    spring:
      datasource:
        url: jdbc:mysql://localhost:3306/tacocloud
        username: root
        password: root   
        # MySQL 8.0 用的驱动不一样
        driver-class-name: com.mysql.jdbc.Driver
        
      sql:
        init:
          mode: always
          platform: mysql
          username: root
          password: root
          schema-locations: classpath*:schema.sql
          data-locations: classpath*:data.sql
    

      使用 MySQL 要引入对应的驱动:

    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>
    

      如果在类路径中存在 Tomcat 的 JDBC 连接池,DataSource 将使用该连接池。否则,Spring Boot 将会在类路径下尝试查找并使用如下的连接池实现:

    • HikariCP
    • Commons DBCP 2

      如果自动配置不能满足需求,可以回到显式配置 DataSource Bean 的模式,这样可以使用任意喜欢的连接池实现。

    (3)配置日志

      默认情况下,Spring Boot 通过 Logback 配置日志,日志会以 INFO 级别写入控制台中。
      可以在 src/main/resources 目录下定义一个 logback.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        
        <!-- spring boot logback日志输出配置颜色转换器 -->
        <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
        <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
        <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
        
        <property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS}  %clr(%-5p) %magenta(${PID:-}) --- [  %t] %cyan(%-40.40logger{39}) : %m%n"/>
        
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <charset>UTF-8</charset>
                <pattern>${PATTERN}</pattern>
            </encoder>
        </appender>
        
        <root level="INFO">
            <appender-ref ref="STDOUT"/>
        </root>
        
        <logger name="root" level="INFO"/>
        
    </configuration>
    

      appender 表示要将日志打印到哪里,默认是 console,也可以指定写入到对应的日志文件。

      要设置日志级别,可以设置 logging.level 作为前缀的属性。随后设置想要设置日志级别的 logger。假设想要将 root logging 设置为 WARN,将 Sping Security 的日志级别设置为 DEBUG,则可在 appliaction.yml 中添加以下配置:

    logging:
      level:
        root: INFO
        org.springframework.security: DEBUG
    

    (4)使用特定的属性值

      除了设置硬编码的属性值,还可以使用 ${} 占位符,表示值来自另外属性。

    greeting:
      welcome: You are using ${spring.application.name}
    

    2、创建和使用自定义配置属性

    (1)定义配置属性的持有者

      定义一个对象,会读取属性配置来注入到成员属性中,

    package tacos;
    
    import javax.validation.constraints.Max;
    import javax.validation.constraints.Min;
    
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    import org.springframework.validation.annotation.Validated;
    
    import lombok.Data;
    
    @Component
    @Data
    @ConfigurationProperties(prefix = "taco.orders")
    @Validated
    public class OrderProps {
    
        @Min(value = 5, message = "must be between 5 and 25")
        @Max(value = 25, message = "must be between 5 and 25")
        private int pageSize;
        
    }
    

      OrderProps 使用了 @Component 注解被定义为一个 bean,使用 @ConfigurationProperties 注解表示为 bean 中那些能够根据 Spring 环境注入值的属性赋值。

      比如这里的 pageSize 就会去找一个 page-size 的属性,因为注解还使用了 taco.orders 的前缀,所以要找的属性是 taco.orders.pageSize

    (2)声明配置属性元数据

      在 application.yml 中,将鼠标悬停在配置的 Spring 自带某个属性上,会介绍该属性使用的一些信息。

      而如果是自定义的属性,会有警告的提示,鼠标悬停显示该属性未知,并且悬停框里还有可点击创建该属性元数据的按钮。

      点击 "Create metadata for xxx" 的按钮,就会自动在 src/main/resources/META-INF 目录下创建一个名为 additional-spring-configuration-metadata.json 的元数据描述 json 文件,打开该文件添加属性描述。

      再次打开 application.yml 可以看到不再有报警了,并且悬停显示 json 文件里添加的描述。

    PS. 如果悬停没有显示 "Create metadata for xxx" 的按钮,则需要安装插件,详情看附录B-问题汇总12。

    3、使用 profile 进行配置

      在不同的环境中,同个属性的值可能是不一样的,这种情况可以使用 Spring Profile,profile 是一种条件化配置,在运行时根据哪些 profile 处于激活状态,可以使用或忽略不同的 bean、配置类和配置属性。

    (1)定义特定的 profile 属性

    方式1:定义不同的 profile 文件

      文件的名称要遵循如下的约定:application-{profile名}.ymlapplication-{profile名}.properties ,比如现在配置两个 yml 文件,一个是 application-dev.yml 用于本地开发测试,一个是 application-prod.yml 用于生产环境。

      application-dev.yml,设置 H2 嵌入内存数据库,spring security 日志级别为 DEBUG。

    spring:
      sql:
        init:
          mode: always
          platform: h2
          username: sa
          password:
          schema-locations: classpath*:schema-h2.sql
          data-locations: classpath*:data-h2.sql
    
      datasource:
        url: jdbc:h2:mem:taco
        username: sa
        password:
        
    logging:
      level:    
        org.springframework.security: DEBUG    
    

      application-prod.yml,设置数据源为 mysql 数据库,spring security 日志级别为 WARN。

    spring:
      sql:
        init:
          mode: always
          platform: mysql
          username: root
          password: root
          schema-locations: classpath*:schema.sql
          #data-locations: classpath*:data.sql
    
      datasource:
        url: jdbc:mysql://localhost:3306/tacocloud
        username: root
        password: root   
        
    logging:
      level:    
        org.springframework.security: WARN    
    

    方式2:在一个 yml 中定义多个 profile

    logging:
      level: 
        tacos: DEBUG
        
    ---
    spring:
      profiles: dev
      
      sql:
        init:
          mode: always
          platform: h2
          username: sa
          password:
          schema-locations: classpath*:schema-h2.sql
          data-locations: classpath*:data-h2.sql
    
      datasource:
        url: jdbc:h2:mem:taco
        username: sa
        password:
        
    logging:
      level:    
        org.springframework.security: DEBUG   
        
    ---
    spring:
      profiles: prod
    
      sql:
        init:
          mode: always
          platform: mysql
          username: root
          password: root
          schema-locations: classpath*:schema.sql
          #data-locations: classpath*:data.sql
    
      datasource:
        url: jdbc:mysql://localhost:3306/tacocloud
        username: root
        password: root   
        
    logging:
      level:    
        org.springframework.security: WARN   
    

      在第一个 --- 上面的属性配置表示适用于所有的 profile,下面的属性表示属于不同的 profile,激活哪个 profile 就用哪些属性配置。如果 profile 的属性设置跟适用于所有 profile 的属性重复,则 profile 里的配置会覆盖优先。

    (2)激活 profile

    方式1:在 yml 中指定(不建议)

    spring:
      profiles:
        active:
        - prod
        - taco
    

    方式2:设置环境参数

    export SPRING_PROFILES_ACTIVE=prod
    

    方式3:命令行参数

    # -Dspring.profiles.active=prod,taco
    java -jar springbootapp.jar --spring.profiles.active=prod,taco
    

    (3)条件化地创建 bean

      有一些场景,我们希望某些 bean 仅在特定 profile 激活的情况下才需要创建,@Profile 注解可以将某些 bean 设置为仅适用于给定的 profile。

    @Bean
    @Profile("prod")
    public User user() {
      new User("Tom", 20);
    }
    

      上面的配置表示当 prod profile 被激活时就注册一个 User 对象的 bean,也可以设置多个 profile 中任一被激活时注册 bean,如:

    @Bean
    @Profile({"prod", "qa"})
    public User user() {
      new User("Tom", 20);
    }
    

      也可以设置某个 profile 被激活时不注册bean,使用 !

    @Bean
    @Profile("!prod")
    public User user() {
      new User("Tom", 20);
    }
    

      同样设置多个 profile 中任一被激活都不注册

    @Bean
    @Profile({"!prod", "!qa"})
    public User user() {
      new User("Tom", 20);
    }
    

    【演示项目github地址】https://github.com/huyihao/Spring-Tutorial/tree/main/2%E3%80%81SpringBoot/taco-cloud-config

    相关文章

      网友评论

        本文标题:Spring Boot 之五:Spring 属性配置

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