Springboot的配置应用环境及字段映射

258 阅读4分钟

前言

在开发中,我们有很多参数需要在不同环境,不同场景下使用,所以我们需要统一的定义到指定的配置文件中,同时我们真正使用的时候必须要映射到代码变量上。这时候我们有可以有多种方式能直接获取到属性值。

配置文件类型和不同的后缀

有yml格式和properties格式,对应不同环境可以通过在名称后面指定-xx的指定环境

  • application.properties / application-xx.properties
  • application.yml / application-xx.yml
  • bootstrap.yml / bootstrap-xx.yml

配置文件的区别

对于propertiesyml格式的区别

  1. application.properties:是一种传统的键值对(key=value)格式的配置文件
  2. application.yml:是 YAML(YAML Ain't Markup Language)格式的配置文件,它使用缩进和层次结构来表示数据。

对于bootstrapapplication的区别

  • bootstrap.yml : 这个文件在应用程序上下文(ApplicationContext)创建之前加载 ,主要配置应用程序基本信息,如springcloud相关配置源信息。
  • application.yml : 在应用程序上下文创建过程中加载 , 用于配置应用程序的具体业务属性。如数据库连接等信息

不同位置的配置文件的优先级

  1. file: ./config/ - 优先级最高(项目根路径下的config)
  2. file: ./ - 优先级第二 -(项目根路径下)
  3. classpath: /config/ - 优先级第三(项目resources/config下)
  4. classpath: / - 优先级第四(项目resources根目录)

编写的方式

对于数组项的编写形式,配置的value具有多项时的场景。

spring.profiles.include:
    - 子项1
    - 子项2
    - 子项3
spring.profiles.include: 子项1,子项2,子项3

如果遇到配置值的需要换一行编写,内容还是连贯的

name: sdfsd\
        sdfdsf

配置生效应用不同场景

Spring Boot 允许通过创建多个以application-{profile}.ymlapplication-{profile}.properties命名的配置文件来指定不同环境的配置。其中{profile}是环境名称

激活配置环境的方式

  1. 通过命令行参数激活: 在启动应用程序时,可以使用--spring.profiles.active=dev
  2. application.ymlapplication.properties中设置默认环境
spring:
  profiles:
    active: dev
  1. 也可以通过@Profile生效环境, 用于在 Bean 的定义或者配置类层面,根据不同的配置文件(profiles)来决定是否创建 Bean 或者使配置类生效。
@Configuration
public class DataSourceConfig {
    @Profile("dev")
    @Bean
    public Student devDataSource() {
        // 配置test环境
        Student stu = new Student();
        stu.setName("gjc");
        stu.setAge(18);
        return devDataSource;
    }
    @Profile("prod")
    @Bean
    public Student prodDataSource() {
        // 配置prod环境
        Student stu = new Student();
        stu.setName("gjc");
        stu.setAge(18);
        return devDataSource;
    }
}
  1. 通过Conditional注解家族的使用
    • @ConditionalOnProperty : 用于根据配置属性的值来决定是否创建一个Bean或者使一个@Configuration类生效
    • @ConditionalOnClass : 用于检查特定的类是否在类路径(classpath)上,以此来决定是否创建Bean或者使@Configuration类生效
    • @ConditionalOnMissingBean : 用于检查容器中是否不存在某个特定类型的Bean,如果不存在,则创建一个新的Bean
    • @ConditionalOnExpression : 基于 SpEL(Spring Expression Language)表达式来决定是否创建Bean或者使@Configuration类生效。
@Configuration
public class MyConfiguration {
    // 只有当配置文件中${stu.name}为18的时候,myService这个Bean才会被创建
    @Bean
    @ConditionalOnProperty(name = "stu.age", havingValue = "18")
    public MyService myService() {
        return new MyService();
    }
    // 只有当类路径上存在这个类,这个bean才会创建
    @Bean
    @ConditionalOnClass(Student.class)
    public TestseService testService() {
        return new TestseService();
    }
    // 只有Spring容器还没创建AnotherService这个bean才会创建这个AnotherServiceBean
    @Bean
    @ConditionalOnMissingBean(AnotherService.class)
    public AnotherService anotherService() {
        return new AnotherService();
    }
    // 只有newService这个Bean只有在服务器端口大于8080并且当前激活的环境是prod时才会被创建
    @Bean
    @ConditionalOnExpression("${server.port} > 8080 && '${spring.profiles.active}' == 'prod'")
    public NewService newService() {
        return new NewService();
    }
}


  1. 自定义实现了@Conditional : 自定义规则,配合自定义注解生效场景。
// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.TYPE)
@Conditional(OnClassNameConditional.class)// 指定规则的内容
public @interface ConditionalOnClassName {
    // 暴露参数value传递
    String value();
}

// 定义规则
public class OnClassNameConditional implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        // 自定义规则判断返回true,或者false 是否生效
    }
}

// 使用注解
@Configuration
@ConditionalOnClassName("com.mysql.jdbc.Driver")
public class MysqlConfiguration extends AbstractJdbcConfiguration{
    @Bean
    public DataSource dataSource() {
        ....
    }
}

获取配置文件属性

通过@Vlaue注解

针对配置文件application.yml/application.properties 中的属性参数

// application.yml
stu:
  name: gjc

// application.properties
stu.name=gjc

配置文件字段直接通过注解@Value映射获取到值。

@Value("${stu.name}")
private String name;

// 设置默认值的方式
@Value("${stu.name:111}")
private String nameDefalut;

注意:

  • 不能作用于静态变量(static);
  • 不能作用于常量(final);
  • 不能在非注册的类中使用(类需要被注册在spring上下文中,如用@Service,@RestController,@Component等);
  • 使用这个类时,只能通过依赖注入的方式,用new的方式是不会自动注入这些配置的。

如果需要使用配置文件字段映射到静态变量上,可以通过如下方式实现,增加静态变量对应的set方法,且再通过注解标识。

private static String userName;

@Value("${stu.name}")
public void setUserName(String userName) {
    UserService.userName = userName;
}

通过@ConfigurationProperties注解

当我们的配置文件对应一个属性下有多个字段,可以将这些字段收整到统一的对象中。

stu:
  name: gjc
  age: 18
  score: 100

@ConfigurationProperties(prefix = "stu")
@Data
public class Student{
    private String name;
    private Integer age;
    private Integer score;
    // 设置别名
    @Value("${stu.score}")
    private Integer currentScore;
}

最后为了使它生效成为一个bean,通过注解@EnableConfigurationProperties(Student.class)标记 或者 @ConfigurationPropertiesScan扫描生效。后面就能通过bean的注入该实体类,就能获取到对应配置属性值。

通过@PropertySource注解使用

@PropertySource是 Spring 框架中的一个注解,用于指定外部属性文件的位置,使得 Spring 能够加载这些文件中的属性,并将其注入到 Spring 管理的 Bean 中。主要也是配合 @Value@ConfigurationProperties联合使用将配置文件值注入字段。

一: 创建自定义外部属性文件custom.properties

stu.name=gjc
stu.age=18

二: 使用@PropertySource注解加载属性文件

通过@PropertySource注解告诉spring在类路径下查找,然后配合@Value加载属性值到字段上。

@Component
@PropertySource("classpath:custom.properties")
public class Test {
    @Value("${stu.name}")
    private String name;
    @Value("${stu.age}")
    private int age;
}

注意:

  • 文件位置可以是相对于类路径(classpath:zz.properties),也可以是绝对路径(file:/xx/yy/zz.properties)
  • 文件格式一般都是.properties

通过class.getClassLoader加载流

通过获取类加载器加载属性文件的方式,也能从配置文件中获取对应的属性。通过配合读取到Properties上来使用。

try {
    // 获取当前类的类加载器
    ClassLoader classLoader = ResourceLoader.class.getClassLoader();
    // 使用类加载器加载属性文件
    InputStream inputStream = classLoader.getResourceAsStream("custom.properties");
    Properties properties = new Properties();
    properties.load(inputStream);
    String propertyValue = properties.getProperty("stu.name");
} catch (IOException e) {
    e.printStackTrace();
}

当然,通过class.getClassLoader 可以加载其他资源文件,例如图片文本等内容。

使用environment对象获取配置属性

Environment是 Spring 框架中的一个接口,用于访问应用程序的运行环境,包括配置属性、系统环境变量、应用程序参数等。可以通过@AutowiredEnvironment对象注入到 Spring 组件中,然后使用getProperty方法获取配置属性

@Component
public class Test{
    @Autowired
    private Environment environment;
    public String getName(){
        return environment.getProperty("stu.name")
    }
}

命令行启动加载配置属性

Spring Boot 允许通过命令行参数来设置配置属性,可以覆盖application.propertiesapplication.yml中设置。

java -jar demo.jar --stu.name=gjc

同理可由上面介绍的几种方法,获取命令行上的参数字段属性。

总结

主要介绍了配置文件的格式,使用和生效环境。以及我们在配置文件中属性值,如何被我们代码所应用上。