• @Profile注解多环境


    @Profile注解

    在容器中如果存在同一类型的多个组件,可以使用@Profile注解标识要获取的是哪一个bean,这在不同的环境使用不同的变量的情景特别有用。例如,开发环境、测试环境、生产环境使用不同的数据源,在不改变代码的情况下,可以使用这个注解来切换要连接的数据库。

    步骤如下:

    1. 在bean上加@Profile注解,其value属性值为环境标识,可以自定义
    2. 使用无参构造方法创建容器
    3. 设置容器环境,其值为第1步设置的环境标识
    4. 设置容器的配置类
    5. 刷新容器

    注:2、4、5步其实是带参构造方法的步骤,相当于把带参构造方法拆开,在其中插入一条语句设置容器环境,这些可以在Spring的源码中可以看出,比如下面的代码。

    public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
       this();
       register(annotatedClasses);
       refresh();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    接下来,看下@Profile注解的源码,如下所示。

    package org.springframework.context.annotation;
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import org.springframework.core.env.AbstractEnvironment;
    import org.springframework.core.env.ConfigurableEnvironment;
    import org.springframework.core.env.Profiles;
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Conditional(ProfileCondition.class)
    public @interface Profile {
    	String[] value();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    注意:@Profile不仅可以标注在方法上,也可以标注在配置类上。如果标注在配置类上,只有在指定的环境时,整个配置类里面的所有配置才会生效。如果一个bean上没有使用@Profile注解进行标注,那么这个bean在任何环境下都会被注册到IOC容器中

    环境模拟

    在项目中新建ProfileConfig配置类,并在ProfileConfig配置类中模拟开发、测试、生产环境的数据源。

    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import javax.sql.DataSource;
    
    /**
     * @author my
     */
    @Configuration
    public class ProfileConfig {
        @Bean("devDataSource")
        public DataSource dataSourceDev() throws Exception{
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test_dev");
            dataSource.setUser("root");
            dataSource.setPassword("root");
            dataSource.setDriverClass("com.mysql.jdbc.Driver");
            return dataSource;
        }
        @Bean("testDataSource")
        public DataSource dataSourceTest() throws Exception{
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test_test");
            dataSource.setUser("root");
            dataSource.setPassword("root");
            dataSource.setDriverClass("com.mysql.jdbc.Driver");
            return dataSource;
        }
        @Bean("prodDataDource")
        public DataSource dataSourceProd() throws Exception{
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test_prod");
            dataSource.setUser("root");
            dataSource.setPassword("root");
            dataSource.setDriverClass("com.mysql.jdbc.Driver");
            return dataSource;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    这个类相对来说比较简单,其中使用 @Bean(“devDataSource”)注解标注的是开发环境使用的数据源;使用 @Bean(“testDataSource”)注解标注的是测试环境使用的数据源;使用@Bean(“prodDataDource”)注解标注的是生产环境使用的数据源。

    测试:

    import org.junit.Test;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import javax.sql.DataSource;
    import java.util.stream.Stream;
    /**
     * @author my
     */
    public class ProfileTest {
        @Test
        public void testProfile01(){
            //创建IOC容器
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProfileConfig.class);
            String[] names = context.getBeanNamesForType(DataSource.class);
            Stream.of(names).forEach(System.out::println);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    运行:

    devDataSource
    testDataSource
    prodDataDource
    
    • 1
    • 2
    • 3

    三种不同的数据源成功注册到了IOC容器

    根据环境注册bean

    成功搭建环境后,接下来,就是要实现根据不同的环境来向IOC容器中注册相应的bean。也就是说,实现在开发环境注册开发环境下使用的数据源;在测试环境注册测试环境下使用的数据源;在生产环境注册生产环境下使用的数据源。此时,@Profile注解就显示出其强大的特性了。

    在ProfileConfig类中为每个数据源添加@Profile注解标识,如下所示。

    @Profile("dev")
    @Bean("devDataSource")
    public DataSource dataSourceDev() throws Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test_dev");
        dataSource.setUser("root");
        dataSource.setPassword("root");
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        return dataSource;
    }
    @Profile("test")
    @Bean("testDataSource")
    public DataSource dataSourceTest() throws Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test_test");
        dataSource.setUser("root");
        dataSource.setPassword("root");
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        return dataSource;
    }
    @Profile("prod")
    @Bean("prodDataDource")
    public DataSource dataSourceProd() throws Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test_prod");
        dataSource.setUser("root");
        dataSource.setPassword("root");
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        return dataSource;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 使用@Profile(“dev”)注解来标识在开发环境下注册devDataSource;
    • 使用@Profile(“test”)注解来标识在测试环境下注册testDataSource;
    • 使用@Profile(“prod”)注解来标识在生产环境下注册prodDataDource。

    运行ProfileTest类的testProfile01()方法,发现命令行并未输出结果信息。说明为不同的数据源添加@Profile注解后,默认是不会向IOC容器中注册bean的,需要根据环境显示指定向IOC容器中注册相应的bean。

    换句话说:通过@Profile注解加了环境标识的bean,只有这个环境被激活的时候,相应的bean才会被注册到IOC容器中。

    默认的环境怎么办?

    可以通过@Profile(“default”)注解来标识一个默认的环境。

    @Profile("default")
    @Bean("devDataSource")
    public DataSource dataSourceDev() throws Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test_dev");
        dataSource.setUser("root");
        dataSource.setPassword("root");
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        return dataSource;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    测试:

    devDataSource
    
    • 1

    可以看到,在devDataSource数据源上使用@Profile(“default”)注解将其设置为默认的数据源,运行测试方法时命令行会输出devDataSource。

    接下来,将devDataSource数据源的@Profile(“default”)注解还原成@Profile(“dev”)注解,标识它为一个开发环境下注册的数据源。

    那么,如何根据不同的环境来注册相应的bean呢?

    第一种方式就是根据命令行参数来确定环境,在运行程序的时候可以添加相应的命令行参数,现在的环境是测试环境,那可以在运行程序的时候添加如下命令行参数。

    -Dspring.profiles.active=test
    
    • 1

    第二种方式就是通过AnnotationConfigApplicationContext类的无参构造方法来实现。在程序中调用AnnotationConfigApplicationContext的无参构造方法来生成IOC容器,在容器进行初始化之前,就为IOC容器设置相应的环境,然后再为IOC容器设置主配置类。将IOC容器设置为生产环境。

    @Test
    public void testProfile02(){
        //创建IOC容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.getEnvironment().setActiveProfiles("prod");
        context.register(ProfileConfig.class);
        context.refresh();
        String[] names = context.getBeanNamesForType(DataSource.class);
        Stream.of(names).forEach(System.out::println);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行testProfile02()方法,输出:

    prodDataDource
    
    • 1

    可以看到,命令行输出了prodDataDource,说明成功将IOC环境设置为了生产环境。

    @Profile不仅可以标注在方法上,也可以标注在配置类上。如果标注在配置类上,只有在指定的环境时,整个配置类里面的所有配置才会生效。例如,在ProfileConfig类上标注@Profile(“dev”)注解。

    @Profile("dev")
    @Configuration
    public class ProfileConfig {
        /*********代码省略*********/
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    运行testProfile02()方法,发现命令行中未输出任何信息。

    这是因为在testProfile02()方法中指定了当前的环境为生产环境,而ProfileConfig类上标注的注解为@Profile(“dev”),说明ProfileConfig类中的所有配置只有在开发环境下才会生效。所以,此时没有任何数据源注册到IOC容器中,命令行不会打印任何信息。

  • 相关阅读:
    unity中实现ue眼球的渲染
    公开的mqtt服务器如何获得等问题
    在虚拟机中新安装的Linux无法联网解决办法
    leetcode top 100 (8)无重复字符的最长子串(滑动窗口
    C++ 继承
    神经网络原理与实例精解,神经网络计算机的组成
    前端控制小数点精度及数字千位分割
    uboot 启动流程详细分析参考
    【Note详细图解】中缀表达式如何转为后缀表达式?数据结构
    和娃一起过暑假:一次4000+km自驾的尝试
  • 原文地址:https://blog.csdn.net/Smy_0114/article/details/126152212