外部化配置

SpringBoot框架默认的配置文件:application.properties

@Value注解

@Value注解可以将application.properties/application.yml文件中的配置信息注入/绑定到java对象的属性上。

语法格式:@Value("${key}")

resources/application.properties文件中进行如下配置:

myapp.username=jack
myapp.email=jack@123.com
myapp.age=30

编写所注入/绑定的对象:

public class User {

    @Value("${myapp.username}")
    private String username;

    @Value("${myapp.email}")
    private String email;

    @Value("${myapp.age}")
    private Integer age;

}

使用@Value注解时也可以指定默认值,当指定默认值时,如果配置文件中没有指定配置值,则采用默认值。

语法格式:@Value("${key:defalut}")

当然,如果配置文件进行了相关的配置,则不会采用默认值

YAML

YAML(YAML Ain't Markup Language)是一种人类可读的数据序列化格式,它通常用于配置文件,在各种编程语言中作为一种存储或传输数据的方式。YAML的设计目标是易于阅读和编写,同时保持足够的表达能力来表示复杂的数据结构。

YAML的语法规则

  1. 数据结构:YAML支持多种数据类型,包括:
    1. 字符串、数字、布尔值
    2. 数组、list集合
    3. map键值对 等。
  2. YAML使用一个空格来分隔属性名属性值,例如:
    1. properties文件中这样的配置:name=jack
    2. yaml文件中需要这样配置:name: jack
  3. YAML用换行+空格来表示层级关系。注意不能使用tab,必须是空格,空格数量无要求,大部分建议2个或4个空格。例如:
    1. properties文件中这样的配置:myapp.name=mall
    2. yaml文件中就需要这样配置:同级元素左对齐。例如:
      myapp:
        name: mall
  4. 同级元素左对齐。例如:

    1. properties`文件中有这样的配置:

      myapp.name=mall
      myapp.count=10
    2. yaml文件中就应该这样配置:

      myapp:
        name: mall
        count: 10
  5. 键必须是唯一的:在一个映射中,键必须是唯一的。
  6. 注释:使用#进行注释。
  7. 大小写敏感

YAML的使用小细节

第一:普通文本也可以使用单引号或双引号括起来:(当然普通文本也可以不使用单引号和双引号括起来。)

  • 单引号括起来:单引号内所有的内容都被当做普通文本,不转义(例如字符串中有\n,则\n被当做普通的字符串)
  • 双引号括起来:双引号中有 \n 则会被转义为换行符

第二:保留文本格式

  •   |    将文本写到这个符号的下层,会自动保留格式。

第三:文档切割

  •  ---   这个符号下面的配置可以认为是一个独立的yaml文件。便于庞大文件的阅读。

配置文件合并

一个项目中所有的配置全部编写到application.properties文件中,会导致配置臃肿,不易维护,有时我们会将配置编写到不同的文件中,例如:application-mysql.properties专门配置mysql的信息,application-redis.properties专门配置redis的信息,最终将两个配置文件合并到一个配置文件中。

properties文件

application-mysql.properties

spring.datasource.username=root
spring.datasource.password=123456

application-redis.properties

spring.data.redis.host=localhost
spring.data.redis.port=6379

application.properties

spring.config.import=classpath:application-mysql.properties,classpath:application-redis.properties

yaml文件

application-mysql.yml

spring:
  datasource:
    username: root
    password: 789789

application-redis.yml

spring:
  data:
    redis:
      host: localhost
      port: 6379

application.yml

spring:
  config:
    import:
      - classpath:application-mysql.yml
      - classpath:application-redis.yml

多环境切换

在Spring Boot中,多环境切换是指在一个应用程序中支持多种运行环境配置的能力。这通常用于区分开发(development)、测试(testing)、预生产(staging)和生产(production)等不同阶段的环境。

开发环境的配置文件名一般叫做:application-dev.properties

spring.datasource.username=dev
spring.datasource.password=dev123
spring.datasource.url=jdbc:mysql://localhost:3306/dev

测试环境的配置文件名一般叫做:application-test.properties

spring.datasource.username=test
spring.datasource.password=test123
spring.datasource.url=jdbc:mysql://localhost:3306/test

预生产环境的配置文件名一般叫做:application-preprod.properties

spring.datasource.username=preprod
spring.datasource.password=preprod123
spring.datasource.url=jdbc:mysql://localhost:3306/preprod

生产环境的配置文件名一般叫做:application-prod.properties

spring.datasource.username=prod
spring.datasource.password=prod123
spring.datasource.url=jdbc:mysql://localhost:3306/prod

如果你希望该项目使用生产环境的配置,你可以这样做:

  • 第一种方式:在application.properties文件中添加这个配置:spring.profiles.active=prod
  • 第二种方式:在命令行参数上添加:**--spring.profiles.active=prod

将配置绑定到bean

绑定简单bean

SpringBoot配置文件中的信息除了可以使用@Value注解读取之外,也可以将配置信息一次性赋值给Bean对象的属性。

例如有这样的配置:

application.yml

app:
  name: jack
  age: 30
  email: jack@123.com

Bean需要这样定义:

package com.powernode.sb307externalconfig.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "app")
public class AppBean {
    private String name;
    private Integer age;
    private String email;

    @Override
    public String toString() {
        return "AppBean{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

说明:

  1. 被绑定的bean,需要使用@ConfigurationProperties(prefix = "app")注解进行标注,prefix用来指定前缀,哪个是前缀,如下图所示:

配置文件中的nameageemail要和bean对象的属性名nameageemail对应上。(属性名相同

并且bean中的所有属性都提供了setter方法。因为底层是通过setter方法给bean属性赋值的。

  1. 这样的bean需要使用@Component注解进行标注,纳入IoC容器的管理。@Component注解负责创建Bean对象,@ConfigurationProperties(prefix = "app")注解负责给bean对象的属性赋值。
  2. bean的属性需要是非static的属性。

@Configuration注解

以上操作中使用了@Component注解进行了标注,来纳入IoC容器的管理。也可以使用另外一个注解@Configuration,用这个注解将Bean标注为配置类。多数情况下我们会选择使用这个注解,因为该Bean对象的属性对应的就是配置文件中的配置信息,因此这个Bean我们也可以将其看做是一个配置类。

@Configuration
@ConfigurationProperties(prefix = "app")
public class AppBean {
    private String name;
    private Integer age;
    private String email;
    //setter and getter 方法
    ......
}

绑定嵌套bean

当一个Bean中嵌套了一个Bean,这种情况下可以将配置信息绑定到该Bean上吗?当然可以。

有这样的一个配置:

app:
  name: jack
  age: 30
  email: jack@123.com
  address: 
    city: BJ
    street: ChaoYang
    zipcode: 123456

需要编写这样的两个Bean:

package com.powernode.sb307externalconfig.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
@ConfigurationProperties(prefix = "app")
public class AppBean {
    private String name;
    private Integer age;
    private String email;
    private Address address;

    @Override
    public String toString() {
        return "AppBean{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                ", address=" + address +
                '}';
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}
package com.powernode.sb307externalconfig.bean;

public class Address {
    private String city;
    private String street;
    private String zipcode;

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getZipcode() {
        return zipcode;
    }

    public void setZipcode(String zipcode) {
        this.zipcode = zipcode;
    }

    @Override
    public String toString() {
        return "Address{" +
                "city='" + city + '\'' +
                ", street='" + street + '\'' +
                ", zipcode='" + zipcode + '\'' +
                '}';
    }
}

@EnableConfigurationProperties与@ConfigurationPropertiesScan

AppBean纳入IoC容器的管理,之前我们说了两种方式:第一种是使用@Component,第二种是使用@Configuration。SpringBoot其实还提供了另外两种方式:

  • 第一种:@EnableConfigurationProperties
  • 第二种:@ConfigurationPropertiesScan

这两个注解都是标注在SpringBoot主入口程序上的:

@EnableConfigurationProperties(AppBean.class)
@SpringBootApplication
public class Sb307ExternalConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(Sb307ExternalConfigApplication.class, args);
    }
}

或者

@ConfigurationPropertiesScan(basePackages = "com.powernode.sb307externalconfig.bean")
@SpringBootApplication
public class Sb307ExternalConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(Sb307ExternalConfigApplication.class, args);
    }
}

将配置赋值到Bean的Map/List/Array属性上

代码如下:

package com.powernode.sb307externalconfig.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

@ConfigurationProperties
public class CollectionConfig {
    private String[] names;
    private List<Product> products;
    private Map<String, Vip> vips;

    @Override
    public String toString() {
        return "CollectionConfig{" +
                "names=" + Arrays.toString(names) +
                ", products=" + products +
                ", vips=" + vips +
                '}';
    }

    public String[] getNames() {
        return names;
    }

    public void setNames(String[] names) {
        this.names = names;
    }

    public List<Product> getProducts() {
        return products;
    }

    public void setProducts(List<Product> products) {
        this.products = products;
    }

    public Map<String, Vip> getVips() {
        return vips;
    }

    public void setVips(Map<String, Vip> vips) {
        this.vips = vips;
    }
}

class Product {
    private String name;
    private Double price;

    @Override
    public String toString() {
        return "Product{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }
}

class Vip {
    private String name;
    private Integer age;

    @Override
    public String toString() {
        return "Vip{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

配置信息如下:application.yml

#数组
names:
  - jackson
  - lucy
  - lili

#List集合
products: 
  - name: 西瓜
    price: 3.0
  - name: 苹果
    price: 2.0

#Map集合
vips:
  vip1:
    name: 张三
    age: 20
  vip2:
    name: 李四
    age: 22

提醒:记得入口程序使用@ConfigurationPropertiesScan(basePackages = "com.powernode.sb307externalconfig.bean")进行标注。

将配置绑定到第三方对象

将配置文件中的信息绑定到某个Bean对象上,如果这个Bean对象没有源码,是第三方库提供的,怎么办?

此时可以单独编写一个方法,在方法上使用以下两个注解进行标注:

  • @Bean
  • @ConfigurationProperties

假设我们有这样一个类Address,代码如下:

package com.powernode.sb307externalconfig.bean;

public class Address {
    private String city;
    private String street;
    private String zipcode;

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getZipcode() {
        return zipcode;
    }

    public void setZipcode(String zipcode) {
        this.zipcode = zipcode;
    }

    @Override
    public String toString() {
        return "Address{" +
                "city='" + city + '\'' +
                ", street='" + street + '\'' +
                ", zipcode='" + zipcode + '\'' +
                '}';
    }
}

当然,我们是看不到这个源码的,只知道有这样一个字节码Address.class。大家也可以看到这个Address类上没有添加任何注解。假设我们要将以下配置绑定到这个Bean上应该怎么做?

address:
  city: TJ
  street: XiangYangLu
  zipcode: 11111111

实现代码如下:

@Configuration
public class ApplicationConfig {
    @Bean
    @ConfigurationProperties(prefix = "address")
    public Address getAddress(){
        return new Address();
    }
}

指定数据来源

之前所讲的内容是将Spring Boot框架默认的配置文件application.propertiesapplication.yml作为数据的来源绑定到Bean上。如果配置信息没有在默认的配置文件中呢?可以使用@PropertySource注解指定配置文件的位置,这个配置文件可以是.properties,也可以是.xml。这里重点掌握.properties即可。

resources目录下新建a目录,在a目录下新建b目录,b目录中新建group-info.properties文件,进行如下的配置:

group.name=IT
group.leader=LaoDu
group.count=20

定义Java类Group,然后进行注解标注:

package com.powernode.sb307externalconfig.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@ConfigurationProperties(prefix = "group")
@PropertySource("classpath:a/b/group-info.properties")
public class Group {
    private String name;
    private String leader;
    private Integer count;

    @Override
    public String toString() {
        return "Group{" +
                "name='" + name + '\'' +
                ", leader='" + leader + '\'' +
                ", count=" + count +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLeader() {
        return leader;
    }

    public void setLeader(String leader) {
        this.leader = leader;
    }

    public Integer getCount() {
        return count;
    }

    public void setCount(Integer count) {
        this.count = count;
    }
}

以下三个注解分别起到什么作用:

  • @Configuration:指定该类为配置类,纳入Spring容器的管理
  • @ConfigurationProperties(prefix = "group"):将配置文件中的值赋值给Bean对象的属性
  • @PropertySource("classpath:a/b/group-info.properties"):指定额外的配置文件

@ImportResource注解

创建Bean的三种方式总结:

  • 第一种方式:编写applicationContext.xml文件,在该文件中注册Bean,Spring容器启动时实例化配置文件中的Bean对象。
  • 第二种方式:@Configuration注解结合@Bean注解。
  • 第三种方式:@Component、@Service、@Controller、@Repository等注解。

第二种和第三种我们都已经知道了。针对第一种方式,如果在SpringBoot框架中应该怎么实现呢?使用@ImportResource注解实现

定义一个普通的Java类:Person

package com.powernode.sb307externalconfig.bean;

public class Person {
    private String name;
    private String age;

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

resources目录下新建applicationContext.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="person" class="com.powernode.sb307externalconfig.bean.Person">
        <property name="name" value="jackson"/>
        <property name="age" value="20"/>
    </bean>
</beans>

在SpringBoot主入口类上添加@ImportResource进行资源导入,这样applicationContext.xml文件中的Bean将会纳入IoC容器的管理:

@ImportResource("classpath:applicationContext.xml")
public class Sb307ExternalConfigApplication {}

编写测试程序,看看是否可以获取到person这个bean对象:

@SpringBootTest
class Sb307ExternalConfigApplicationTests {
    @Autowired
    private Person person;
    @Test
    void test09(){
        System.out.println(person);
    }
}

因此,项目中如果有类似于Spring的这种xml配置文件,要想纳入IoC容器管理,需要在入口类上使用@ImportResource("classpath:applicationContext.xml")注解即可。

Environment

SpringBoot框架在启动的时候会将系统配置,环境信息全部封装到Environment对象中,如果要获取这些环境信息,可以调用Environment接口的方法。

在Spring Boot中,Environment接口提供了访问应用程序环境信息的方法,比如活动配置文件、系统环境变量、命令行参数等。Environment接口由Spring框架提供,Spring Boot应用程序通常会使用Spring提供的实现类AbstractEnvironment及其子类来实现具体的环境功能。

Environment对象封装的主要数据包括:

  1. Active Profiles: 当前激活的配置文件列表。Spring Boot允许应用程序定义不同的环境配置文件(如开发环境、测试环境和生产环境),通过激活不同的配置文件来改变应用程序的行为。
  2. System Properties: 系统属性,通常是操作系统级别的属性,比如操作系统名称、Java版本等。
  3. System Environment Variables: 系统环境变量,这些变量通常是由操作系统提供的,可以在启动应用程序时设置特定的值。
  4. Command Line Arguments: 应用程序启动时传递给主方法的命令行参数。
  5. Property Sources: Environment还包含了一个PropertySource列表,这个列表包含了从不同来源加载的所有属性。PropertySource可以来自多种地方,比如配置文件、系统属性、环境变量等。

在Spring Boot中,可以通过注入Environment来获取上述信息。例如:

package com.powernode.springboot.bean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Component
public class SomeBean {

    @Autowired
    private Environment environment;

    public void doSome(){
        // 直接使用这个环境对象,来获取环境信息,配置信息等。
        String[] activeProfiles = environment.getActiveProfiles();
        for (String activeProfile : activeProfiles) {
            System.out.println(activeProfile);
        }

        // 获取配置信息
        String street = environment.getProperty("app.xyz.addr.street");
        System.out.println(street);
    }
}

通过这种方式,你可以根据环境的不同灵活地配置你的应用程序。Environment是一个非常有用的工具,它可以帮助你管理各种类型的配置信息,并根据不同的运行时条件做出相应的调整。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值