Spring之@Value注解

前言

@Value注解在Spring的依赖注入中占据重要地位,这里对@Value注解的作用进行演示以及扩展

作用

  • 注入字符串
  • 注入属性
  • 注入bean
  • 其他

代码准备

创建两个普通的bean

@Component
public class ValueComponent {
}
@Component
public class Foo {

    private String sign;

    public Foo() {
        this.sign = UUID.randomUUID().toString().replaceAll("-", "");
    }

    public String getSign() {
        return sign;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }
}

创建配置文件val.properties

key=source
source=spring
color=blank,white,red

创建配置类

@ComponentScan("com.test.val")
@PropertySource("classpath:val.properties")
public class AppConfig {

}

创建启动类

public class Main {

    public static void main(String[] args) {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    }
}

示例

注入字符串

@Component
public class ValueComponent {

    @Value("hello world")
    private String helloWorld;

}

注入属性

注入普通属性
@Component
public class ValueComponent {

    @Value("${key}")
    private String key;

}

注入嵌套属性
@Component
public class ValueComponent {

    @Value("${${key}}")
    private String nestKey;

}

 注入的属性不存在
@Component
public class ValueComponent {

    @Value("${server.port}")
    private String absentKey;

}

PS : Spring默认情况下使用的是宽松模式, 解析不了的属性等于注入了字符串

注入的属性不存在,使用默认值
@Component
public class ValueComponent {

    @Value("${server.port:8080}")
    private String absentDefaultKey;

}

注入bean及其属性

@Component
public class ValueComponent {

    @Value("#{foo}")
    private Foo foo;

    @Value("#{foo['sign']}")
    private String sign;
}

其他

@Component
public class ValueComponent {

    @Value("https://www.baidu.com/")
    private URL url;

    @Value("classpath:val.properties")
    private Resource resource;

}

属性注入优先级问题

创建配置文件val2.properties 

key=source2
source=spring2

 修改配置文件

@ComponentScan("com.test.val")
@PropertySources({@PropertySource("classpath:val.properties"), @PropertySource("classpath:val2.properties")})
public class AppConfig {

}

注入普通属性key

@Component
public class ValueComponent {

    @Value("${key}")
    private String key;

}

Spring默认情况下创建的Environment是StandardEnvironment,会添加两个默认PropertySource : systemProperties systemEnvironment

系统默认添加的两个PropertySource优先级最高,使用@PropertySource(@PropertySources)注解导入的propertySource,越先解析优先级越低

当前环境的PropertySource排序

systemProperties > systemEnvironment > val2.properties > val1.properties 

如果在优先级较高的PropertySource里面找到了相关属性,则直接返回不会查找优先级较低的PropertySource了

Springboot对Spring做了很多扩展, 存在很多PropertySource

对@Value属性注入的扩展

如果beanFactory中不存在embeddedValueResolvers则会添加一个默认的embeddedValueResolvers

AbstractApplicationContext#finishBeanFactoryInitialization

DefaultListableBeanFactory#doResolveDependency

AbstractBeanFactory#resolveEmbeddedValue

在上述的前提下我们可以自定义一个StringValueResolver来解析@Value注解传入的字符串

创建MergedResolver对象

public class MergedResolver implements StringValueResolver {

    private PropertySources propertySources;

    private final PropertySourcesPropertyResolver defaultResolver;

    private final PropertySourcesPropertyResolver resolver1;

    private final PropertySourcesPropertyResolver resolver2;

    public MergedResolver(PropertySources propertySources) {
        this.propertySources = propertySources;

        defaultResolver = new PropertySourcesPropertyResolver(this.propertySources);

        resolver1 = new PropertySourcesPropertyResolver(this.propertySources);
        resolver1.setPlaceholderPrefix("$[");
        resolver1.setPlaceholderSuffix("]");

        resolver2 = new PropertySourcesPropertyResolver(this.propertySources);
        resolver2.setPlaceholderPrefix("$(");
        resolver2.setPlaceholderSuffix(")");
    }

    @Override
    public String resolveStringValue(String strVal) {
        if (strVal.startsWith("$[")) {
            return resolver1.resolvePlaceholders(strVal);
        } else if (strVal.startsWith("$(")) {
            return resolver2.resolvePlaceholders(strVal);
        } else {
            return defaultResolver.resolvePlaceholders(strVal);
        }
    }
}

创建StringValueResolverImporter对象

public class StringValueResolverImporter implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private Environment environment;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) registry;
        // 添加自定义EmbeddedValueResolver
        // 自定义的EmbeddedValueResolver要兼容默认的EmbeddedValueResolver,否则默认的@Value功能全部失效
        // 一定要兼容默认的EmbeddedValueResolver 一定要兼容默认的EmbeddedValueResolver 一定要兼容默认的EmbeddedValueResolver
        // 重要的事情说三遍 ! ! !
        beanFactory.addEmbeddedValueResolver(new MergedResolver(((StandardEnvironment) environment).getPropertySources()));
    }

}

修改配置文件

@ComponentScan("com.test.val")
@Import(StringValueResolverImporter.class)
@PropertySources({@PropertySource("classpath:val.properties"), @PropertySource("classpath:val2.properties")})
public class AppConfig {

}

修改ValueComponent

@Component
public class ValueComponent {

    @Value("${key}")
    private String key1;

    @Value("$[key]")
    private String key2;

    @Value("$(key)")
    private String key3;

}

运行Main方法,查看运行结果

Springboot对@Value类型转换的扩展

修改ValueComponent

@Component
public class ValueComponent {

    @Value("${color}")
    private List<String> color;
}

如果使用的是SpringBoot,会将字符串以逗号分割,然后放入list中

主要原因是Springboot给BeanFactory添加了一个ApplicationConversionService,这个类的默认构造方法会添加很多convert

通过源码我们知道了这个扩展点可以使用@Delimiter指定分隔符,然后默认分隔符是逗号

使用Spring达到同样效果

复用StringValueResolverImporter代码

 修改val.properties

key=source
source=spring
color=blank,white,red
car=redCar;whiteCar;blackCar

修改ValueComponent

@Component
public class ValueComponent {

    @Value("${color}")
    private List<String> color;

    @Value("${car}")
    @Delimiter(";")
    private List<String> car;
}

运行Main方法,查看运行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/469956.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux编译器--gcc/g++的使用

1. gcc与g gcc与g分别是c语言与c代码的编译器&#xff0c;但同时g也兼容c语言。 我们知道在Linux中&#xff0c;系统并不以文件后缀来区分文件类别。但对于gcc与g等编译器而言却是需要的。Linux中c代码文件的后缀是.c&#xff0c;c代码文件的后缀是.cpp(.cc)(.cxx)。 在Linu…

linux安装Redis且搭建主从、哨兵、集群以及使用(超详细)

一.Redis简介 1.NoSQL简介 ​ 目前市场主流数据存储都是使用关系型数据库。每次操作关系型数据库时都是I/O操作&#xff0c;I/O操作是主要影响程序执行性能原因之一&#xff0c;连接数据库关闭数据库都是消耗性能的过程。尽量减少对数据库的操作&#xff0c;能够明显的提升程…

Nodejs 第五十八章(大文件上传)

在现代网站中&#xff0c;越来越多的个性化图片&#xff0c;视频&#xff0c;去展示&#xff0c;因此我们的网站一般都会支持文件上传。 文件上传的方案 大文件上传&#xff1a;将大文件切分成较小的片段&#xff08;通常称为分片或块&#xff09;&#xff0c;然后逐个上传这…

体育运动直播中的智能运动跟踪和动作识别系统 - 视频分析如何协助流媒体做出实时决策

AI-Powered Streaming Vision: Transforming Real-Time Decisions with Video Analytics 原著&#xff1a;弗朗西斯科冈萨雷斯&#xff5c;斯特朗&#xff08;STRONG&#xff09;公司首席ML科学家 翻译&#xff1a;数字化营销工兵 实时视频分析通过即时处理实时视频数据&…

【故障排查】10分钟解决Quartz重复调度的疑难杂症

我司使用Apache DolphinScheduler作为调度框架很久了&#xff0c;感兴趣的小伙伴可以看看这些干货文章&#xff1a; 因为之前监控到会出现重复的调度的问题&#xff0c;所以此文记录排查重复调度问题的全过程&#xff0c;希望对社区其他的小伙伴能够起到抛砖引玉的作用&#x…

1.中医学习-总论

目录 1.为什么要学中医 2.什么是中医 介绍 中医例子1&#xff1a; 中医例子2: 中医最高境界“大道至简” 中医讲究的是本质 中医核心&#xff1a;阴阳、表里、寒热、虚实 ​编辑医不叩门 3.阴阳 1.一天中的阴阳 2.一年中的阴阳 3.阴阳之间的关系 4.阴阳四季的变化 …

JetBrains学生包续期

Pycharm进入显示your license has expired 这个意思是你的许可过期了&#xff0c;重新输入最新的激活码就可以了。 1. 说明我的JetBrains学生包需要进行续期了。首先登录JetBrains官网打开个人主页&#xff0c;点击Renew my Education Pack 2. 然后填写一系列信息&#xff0c;…

户用光伏OA管理系统——光伏企业管理的新利器

随着全球对可再生能源的重视和推广&#xff0c;光伏行业得到了快速的发展&#xff0c;为人们提供了清洁、可再生能源。户用光伏作为光伏行业中应用最为广泛的发电系统&#xff0c;可以安装在居民住宅等地。越来越多的人们对户用光伏的发展给予支持&#xff0c;给光伏企业管理带…

PHP+MySQL开发组合:多端多商户DIY商城源码系统 带完整的搭建教程以及安装代码包

近年来&#xff0c;电商行业的迅猛发展&#xff0c;越来越多的商户开始寻求搭建自己的在线商城。然而&#xff0c;传统的商城系统往往功能单一&#xff0c;无法满足商户个性化、多样化的需求。同时&#xff0c;搭建一个功能完善的商城系统需要专业的技术团队和大量的时间成本&a…

OpenCV4.9.0在windows系统下的安装

返回&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一章&#xff1a;将 OpenCV 与 Eclipse 结合使用&#xff08;插件 CDT&#xff09; 下一章&#xff1a;未发表 警告&#xff1a; 本教程可以包含过时的信息. 此处的描述已在 Windows 7 SP1 上…

FMQL45 XADC

通过PL自带的XADC可以读写温度&#xff0c;电压等&#xff0c;但是总是读的不对。开始查找FM_QL_bsp里面少了一个部分就是pl&#xff01;添加&#xff0c;在ewp已经修改了&#xff0c;但是文件不存在&#xff0c;现在给补上了&#xff0c;有点奇怪&#xff0c;有的项目会自动生…

ConKI: Contrastive Knowledge Injection for Multimodal Sentiment Analysis

文章目录 ConKI&#xff1a;用于多模态情感分析的对比知识注入文章信息研究目的研究内容研究方法1.总体结构2.Encoding with Knowledge Injection2.1 Pan-knowledge representations2.2 Knowledge-specific representations 3.Hierarchical Contrastive Learning4.损失函数5.训…

发布镜像到阿里云仓库

发布上一篇Dockerfile实战-自定义的centos镜像。 1、登录阿里云 2、找到容器镜像服务 3、创建命令空间 4、创建镜像仓库 5、点击进入这个镜像仓库&#xff0c;可以看到所有的信息 6、根据操作指南测试推送发布 6.1登录阿里云 [rootzhoujunru home]# docker login --usernam…

【问题记录】自定义Prometheus exporter收集数据,Prometheus显示收集到数据,grafana未显示数据出来

问题背景&#xff1a; 使用golang编写Prometheus exporter&#xff0c;获取指定API Url返回值中的data值&#xff0c;把它做为自定义指标。 1、exporter 500ms自动更新一次data值 2、Prometheus的Graph界面输入自定义指标可以查询到值的变化 3、自定义指标最小时间是ms级别&…

es 集群安全认证

参考文档&#xff1a;Configure security for the Elastic Stack | Elasticsearch Guide [7.17] | Elastic ES敏感信息泄露的原因 Elasticsearch在默认安装后&#xff0c;不提供任何形式的安全防护不合理的配置导致公网可以访问ES集群。比如在elasticsearch.yml文件中,server…

数据在内存中的的存储

1.数据类型介绍 内置类型 char , short , int , long , float , double , long long (C99) long 类型的大小是 4 / 8 个字节&#xff0c;元素C语言规定 sizeof&#xff08;long&#xff09;> sizeof&#xff08;int&#xff09;就行。在32位平台上&#xff0c;long为4个字…

完整指南:如何使用 Stable Diffusion API

Stable Diffusion 是一个先进的深度学习模型&#xff0c;用于创造和修改图像。这个模型能够基于文本描述来生成图像&#xff0c;让机器理解和实现用户的创意。使用这项技术的关键在于掌握其 API&#xff0c;通过编程来操控图像生成的过程。 在探索 Stable Diffusion API 的世界…

循环链表的用法

7.设 数 组 data[m] 作 为 循 环 队 列 SQ 的 存 储 空 间 &#xff0c;front 为 队 头 指 针 &#xff0c;rear 为 队 尾 指 针 &#xff0c;则 执 行 出 队 操 作 后 其 头 指 针 front 值 为 &#xff08; &#xff09; A&#xff0e;frontfront1 B&#xff0e;front(front1…

上位机图像处理和嵌入式模块部署(qmacvisual自己编写算法插件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们说过&#xff0c;qmacvisual本身支持52个控件&#xff0c;但是指望这52个控件可以cover所有的应用场景&#xff0c;这也不太现实。另外&am…

【DBC专题】-11-使用Cantools将CAN/CANFD DBC自动生成C语言代码

目录 1 安装Python和Cantools 1.1 查看Python已安装的Package包 1.2 在Python中安装Cantools插件包 1.3 获取更多Cantools工具的更新动态 2 经典CAN/CANFD DBC自动生成C语言代码 2.1 批处理文件CAN_DBC_To_C.bat内容说明 2.2 经典CAN/CANFD DBC文件要求 2.3 如何使用生…