Spring源码从入门到精通---@Profile(十五)

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: Spring源码从入门到精通---@Profile(十五)

上篇文章主要说了Aware接口:

如何吧spring底层组件赋值到自定义组件里呢,可以实现xxxAware接口,比如实现ApplicationContextAware接口,可以获取到applicationContext。这些都是由xxxAwareProcessor后置处理器处理的,如ApplicationContextAwareProcessor,先创建bean之后,后置处理器处理吧对应的数据赋值。

Aware&原理---Spring源码从入门到精通(十四)


这篇文章主要说@Profile:

文章分为两个部分,第一部分,数据源环境的搭建。第二部分,@Profile能根据开发环境和测试环境,加在不同的数据源,所以第二部分,如何通过spring提供的@Profile注解,根据我们当前的开发环境,动态的激活和切换一系列组件。


一、数据源环境搭建


先贴一份本文目录

image.png

首先创建myConfigProfile类,创建dataSource.properties配置文件,用我们之前学到过的@PropertySource注解指定加载的配置文件,用三种不同的方法获取到配置文件里面的值,都是我们之前学到过得。


1)、@Value普通获取值

2)、在方法参数上用@Value获取值

3)、实现EmbeddedValueResolverAware接口,解析器获取运行环境里面的值。


配置文件如下:

dataName=root
dataPassword=root
data.driver.class=com.mysql.jdbc.Driver

新的配置类如下:

/**
 * @Profile:根据我们的当前环境,动态的激活和切换一系列组件。
 * 如test环境用test配置,dev环境用dev配置
 *
 * @author keying
 */
@PropertySource(value = {"classpath:/dataSources.properties"})
@Configuration
public class MyConfigProfile implements EmbeddedValueResolverAware {
    @Value("${dataName}")
    private String user;
    private String driverClass;
    @Bean("testDataSource")
    public DataSource test(@Value("${dataPassword}") String password) throws Exception {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        comboPooledDataSource.setPassword(password);
        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/testmac");
        comboPooledDataSource.setDriverClass(driverClass);
        return comboPooledDataSource;
    }
    @Bean("devDataSource")
    public DataSource dev(@Value("${dataPassword}") String password) throws Exception {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        comboPooledDataSource.setPassword(password);
        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/dev");
        comboPooledDataSource.setDriverClass(driverClass);
        return comboPooledDataSource;
    }
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        //配置文件信息放入环境里,解析器从环境信息中获取
        this.driverClass = resolver.resolveStringValue("${data.driver.class}");
    }
}
/**
 * @author keying
 */
public class IOCTestProfile {
    @Test
    public void test() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
            MyConfigProfile.class);
        //根据类型获取数据源
        String[] strings = applicationContext.getBeanNamesForType(DataSource.class);
        for(String string:strings){
            System.out.println(string);
        }
    }
}

通过junitTest打印可以看到,可以获取我们的两个数据源。本文演示是链接mysql数据库两个不同的database,同学请先在电脑上安装mysql数据库并建立好test和dev两个数据库,不知道安装mysql的自行百度。

image.png

二、@Profile注解使用


1、默认会加载@Profile("default"),指定组件在哪个环境才会注册到容器中,否则都不会注册到IOC容器。


2、改为加载test数据源:

* 1)使用命令行参数,在虚拟机参数位子加:-Dspring.profile.active=test

* 2)使用代码的方式,代码不能用有参构造器加载,从源码可以看到,配置类直接加载,就不能改系统环境里面的值。用无参构造器refresh()容器,其实就是源码里的三步,第一步this()无参创建对象,第二部register注册配置类,第三部刷新创建容器。

* 3)没有配置@Profile的bean,不管在哪个环境都能加载。@Profile可以写在方法上,选择加载指定环境的配置组件。写在配置类上,只有满足当前环境,整个类才会加载。


/**
 * @author keying
 */
public class IOCTestProfile {
    /**
     * 1、默认会加载@Profile("default"),指定组件在哪个环境才会注册到容器中,否则都不会注册到IOC容器。
     * 2、改为加载test数据源:
     * 1)使用命令行参数,在虚拟机参数位子加:-Dspring.profile.active=test
     * 2)使用代码的方式,代码不能用有参构造器加载,从源码可以看到,配置类直接加载,就不能改系统环境里面的值。
     * 用无参构造器refresh()容器,其实就是源码里的三步,第一步this()无参创建对象,第二部register注册配置类,第三部刷新创建容器。
     * 3)没有配置@Profile的bean,不管在哪个环境都能加载。
     *
     * @Profile可以写在方法上,选择加载指定环境的配置组件。写在配置类上,只有满足当前环境,整个类才会加载。
     */
    @Test
    public void test() {
        //第一步创建applicationContext对象
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
        );
        //第二部设置需要激活的环境
        ConfigurableEnvironment configurableEnvironment = applicationContext.getEnvironment();
        configurableEnvironment.setActiveProfiles("test");
        //第三部注册主配置类
        applicationContext.register(MyConfigProfile.class);
        //第四部刷新启动
        applicationContext.refresh();
        //根据类型获取数据源
        String[] strings = applicationContext.getBeanNamesForType(DataSource.class);
        for (String string : strings) {
            System.out.println(string);
        }
        Yellow yellow = applicationContext.getBean(Yellow.class);
        System.out.println(yellow);
        applicationContext.close();
    }
}
/**
 * @author keying
 * @Profile:根据我们的当前环境,动态的激活和切换一系列组件。如test环境用test配置,dev环境用dev配置
 */
@PropertySource(value = {"classpath:/dataSources.properties"})
@Configuration
//@Profile("test")
public class MyConfigProfile implements EmbeddedValueResolverAware {
    @Value("${dataName}")
    private String user;
    private String driverClass;
    @Bean
    public Yellow yellow(){
        return new Yellow();
    }
    @Profile("test")
    @Bean("testDataSource")
    public DataSource test(@Value("${dataPassword}") String password) throws Exception {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        comboPooledDataSource.setPassword(password);
        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/testmac");
        comboPooledDataSource.setDriverClass(driverClass);
        return comboPooledDataSource;
    }
    @Profile("dev")
    @Bean("devDataSource")
    public DataSource dev(@Value("${dataPassword}") String password) throws Exception {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        comboPooledDataSource.setPassword(password);
        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/dev");
        comboPooledDataSource.setDriverClass(driverClass);
        return comboPooledDataSource;
    }
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        //配置文件信息放入环境里,解析器从环境信息中获取
        this.driverClass = resolver.resolveStringValue("${data.driver.class}");
    }
}

从打印可以看出来,yellow在设置了test环境之后,还是 能打印出来,并且profile注解配置了dev的就打印不出来。

image.png


问:@Confitional注解和@Profile注解都能用在类上,并且都是不满足就不加载,有什么不同?


@Profile是修改系统环境的数据,需要在ioc容器refresh()之前设置,所以不能用有参构造加载配置类。

@Conditional则是在可以获取到环境里面的值,在进行过滤判断,如获取当前运行环境或者系统,进行过滤。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
XML 缓存 Java
Spring源码之 Bean 的循环依赖
循环依赖是 Spring 中经典问题之一,那么到底什么是循环依赖?简单说就是对象之间相互引用, 如下图所示: 代码层面上很好理解,在 bean 创建过程中 class A 和 class B 又经历了怎样的过程呢? 可以看出形成了一个闭环,如果想解决这个问题,那么在属性填充时要保证不二次创建 A对象 的步骤,也就是必须保证从容器中能够直接获取到 B。 一、复现循环依赖问题 Spring 中默认允许循环依赖的存在,但在 Spring Boot 2.6.x 版本开始默认禁用了循环依赖 1. 基于xml复现循环依赖 定义实体 Bean java复制代码public class A {
|
1月前
|
Java 测试技术 数据库
SpringBoot:@Profile注解和Spring EL
SpringBoot:@Profile注解和Spring EL
|
10天前
|
前端开发 Java 数据库连接
Spring系列文章1:Spring入门程序
Spring系列文章1:Spring入门程序
|
1月前
|
Java 测试技术 数据库连接
【Spring源码解读!底层原理高级进阶】【下】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨
【Spring源码解读!底层原理高级进阶】【下】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨
|
1天前
|
Java 关系型数据库 MySQL
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。一套UWB精确定位系统,最高定位精度可达10cm,具有高精度,高动态,高容量,低功耗的应用。
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
|
7天前
|
XML Java 数据格式
从入门到精通:Spring基础注解的全面解析
从入门到精通:Spring基础注解的全面解析
22 2
从入门到精通:Spring基础注解的全面解析
|
27天前
|
存储 缓存 安全
Spring Boot从入门到实战
本课程从SpringBoot的最基础的安装、配置开始到SpringBoot的日志管理、Web业务开发、数据存储、数据缓存,安全控制及相关企业级应用,全程案例贯穿,案例每一步的都会讲解实现思路,全程手敲代码实现。让你不仅能够掌SpringBoot的应用,还能了解背后的原理,学习完本课程后,能够让你动手独立完成一个中小型的SpringBoot Web应用开发。
19 1
Spring Boot从入门到实战
|
30天前
|
Java Spring
使用spring实现邮件的发送(含测试,源码,注释)
使用spring实现邮件的发送(含测试,源码,注释)
7 0
|
1月前
|
Java Spring 容器
【Spring源码】单例创建期间进行同步可能会导致死锁?
通过这个标题我们就可以思考本次的阅读线索了,看起来可以学到不少东西。1. 旧代码的死锁是怎么产生的。2. 贡献者通过改变什么来解决本次PR的问题呢?而阅读线索2的答案也显而易见,就是上文提到的通过后台线程来创建Micrometer单例...
41 3
|
21天前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
38 0