关于spring:spring注解驱动开发9-Profile多配置文件容器的注册选择

有时候咱们有两个配置文件, 一个是dev环境的, 一个是线上product环境的, 在开发的时候, 启动加载dev配置文件, 上线后启动应用product的配置; 这里就能够用到@Profile的性能;

其原理就是在上下文启动的时候, 通过扭转一个环境参数(-Dspring.profiles.active=xxx)的值, 让spring去抉择加载和初始化对应的profile;

举例: 咱们有两套数据源配置: devproduct; 配置区别大体如下:

  1. 配置文件: src\main\resources\db.properties
dev.mysql.url = jdbc:mysql://127.0.0.1/dev
dev.mysql.username = niewj
dev.mysql.password = 123456
dev.mysql.validationQuery = SELECT 1

#-----------------
product.mysql.url = jdbc:mysql://niewj.com/product
product.mysql.username = root
product.mysql.password = 654321
product.mysql.validationQuery = SELECT 1
  1. 配置注解文件: ProfilesDatasourceConfig.java
package com.niewj.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource("classpath:/db.properties")
public class ProfilesDatasourceConfig {

    /**
     * product 配置
     */
    @Value("${product.mysql.url}")
    private String urlProduct;
    @Value("${product.mysql.username}")
    private String usernameProduct;
    @Value("${product.mysql.password}")
    private String passwordProduct;
    /**
     * dev 配置
     */
    @Value("${dev.mysql.url}")
    private String urlDev;
    @Value("${dev.mysql.username}")
    private String usernameDev;
    @Value("${dev.mysql.password}")
    private String passwordDev;

    /**
     * 其余通用配置
     */
    @Value("${dev.mysql.validationQuery}")
    private String validationQuery = "SELECT 1";

    @Profile("dev")
    @Bean
    public DruidDataSource dataSourceDev(){
        DruidDataSource ds = new DruidDataSource();
        ds.setUrl(urlDev);
        ds.setUsername(usernameDev);
        ds.setPassword(passwordDev);
        ds.setValidationQuery(validationQuery);
        System.out.println("初始化-dev-druidDataSource");

        return ds;
    }

    @Profile("product")
    @Bean
    public DruidDataSource dataSourceProduct(){
        DruidDataSource ds = new DruidDataSource();
        ds.setUrl(urlProduct);
        ds.setUsername(usernameProduct);
        ds.setPassword(passwordProduct);
        ds.setValidationQuery(validationQuery);

        System.out.println("初始化-product-druidDataSource");
        return ds;
    }
}
  1. 测试用例: src\test\java\com\niewj\ProfileTest.java
package com.niewj;

import com.alibaba.druid.pool.DruidDataSource;
import com.niewj.config.ProfilesDatasourceConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.stream.Stream;

/**
 * spring profile测试
 */
public class ProfileTest {

    @Test
    public void testProfile() {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.register(ProfilesDatasourceConfig.class);
        ctx.getEnvironment().setActiveProfiles("product"); // 1
        // ctx.getEnvironment().setActiveProfiles("dev"); // 2
        ctx.refresh();

        // 打印spring容器中的 BeanDefinition
        Stream.of(ctx.getBeanDefinitionNames()).forEach(e -> System.out.println(e));
        System.out.println("=============================");
        DruidDataSource ds = null;
        if ((ds = ctx.getBean(DruidDataSource.class)) != null) {
            System.out.println(ds);
        }

        ctx.close();
    }

}

这里有两种形式能够实现调用:

1. 批改spring上下文的Environment参数

结构器初始化时不传入加载配置类; 而是初始化后, 上下文手动注册配置类, 而后批改active profiles, 最初refresh上下文;

其实传入配置类的结构器的源码如下: 咱们如果应用它, 就无奈批改环境参数并refresh了, 所以注册的事件咱们本人来干!

    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        this();
        register(componentClasses);
        refresh();
    }

咱们这么操作, 输入如下:

output: 可见是加载了 product的profile; 同样 换了 dev亦然!

初始化-product-druidDataSource
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
profilesDatasourceConfig
dataSourceProduct
=============================
{
    CreateTime:"2020-07-17 17:11:46",
    ActiveCount:0,
    PoolingCount:0,
    CreateCount:0,
    DestroyCount:0,
    CloseCount:0,
    ConnectCount:0,
    Connections:[
    ]
}
七月 17, 2020 5:11:46 下午 com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl info
信息: {dataSource-0} closing ...

2. 执行加参数-Dspring.profiles.active=product

应用结构器注册配置类, 而后执行的时加参数-Dspring.profiles.active=product来触发调用, 达到目标;

(1). 结构器初始化加载配置类:

    @Test
    public void testProfileConstructure() {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ProfilesDatasourceConfig.class);

        // 打印spring容器中的 BeanDefinition
        Stream.of(ctx.getBeanDefinitionNames()).forEach(e -> System.out.println(e));
        System.out.println("=============================");
        DruidDataSource ds = null;
        if ((ds = ctx.getBean(DruidDataSource.class)) != null) {
            System.out.println(ds);
        }

        ctx.close();
    }

(2). 执行时加参数 -Dspring.profiles.active=product , 这种形式 输入也和下面一样的, output 略去

3. 小结:

(1). deault: 多个 @Profile("dev") @Profile("product") , 如果执行时没有手动加参数: -Dspring.profiles.active=xxx 默认只会寻找@Profile("default")的; 没有的话, 就都不会在容器中初始化;

(2). 如果@Profile("dev")是在配置类上注解的, 类下所有的操作只有在匹配到执行时 -Dspring.profiles.active=dev时, 才会初始化, 否则, 甚至连配置类自身都不会初始化注册到容器;

(3). 顺着(2)的阐明, 如果执行时-Dspring.profiles.active=dev, 类上的注解也是@Profile("dev"), 此配置类中没有@Profile注解的 @Bean办法都会失常初始化注册到容器; 只有不匹配的@Profile("xxx")不会注册;

(4). ctx.getEnvironment().setActiveProfiles("product"),能够设置多个: ctx.getEnvironment().setActiveProfiles("product", "dev")

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理