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(")");}@Overridepublic 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;@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}@Overridepublic 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方法,查看运行结果

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

day-24 不同路径

思路&#xff1a;动态规划&#xff0c;因为只能向下或向右移动&#xff0c;所以第一行和第一列的路径数皆为1&#xff0c;其余位置的路径数dp[i][j]dp[i-1][j]dp[i][j-1] 最后返回dp[m-1][n-1]即可 code: class Solution {public int uniquePaths(int m, int n) {int dp[][]n…

【通用知识】HttpServletRequest接口方法

一、前端知识概述 说明&#xff1a; 1、Headers和Payload为前端传给后端的请求头和请求参数信息。Preview和Response为后端返回的数据。 2、Payload标签内为前端传给后端的参数。其中&#xff0c;Query String Parameters中为问号传参&#xff0c;对应后端RequestParam方式&…

MNN createRuntime(二)

系列文章目录 MNN createFromBuffer&#xff08;一&#xff09; MNN createRuntime&#xff08;二&#xff09; MNN createSession 之 Schedule&#xff08;三&#xff09; MNN createSession 之创建流水线后端&#xff08;四&#xff09; MNN Session::resize 之流水线编码&am…

C# Onnx Yolov9 Detect 物体检测

目录 介绍 效果 项目 模型信息 代码 下载 C# Onnx Yolov9 Detect 物体检测 介绍 yolov9 github地址&#xff1a;https://github.com/WongKinYiu/yolov9 Implementation of paper - YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information …

软件工程-第6章 面向对象方法UML

UML是一种图形化语言&#xff0c;简称画图。 6.1 表达客观事物的术语 6.2 表达关系的术语 1.关联 表达关联语义相关术语&#xff1a;关联名、导航、角色、可见性、多重性、限定符、聚合、组合。 2.泛化 3.细化 6.3 组织信息的一种通用机制-包 6.4 模型表达工具 一个用况图包含6…

Springboot+Redis:实现缓存 减少对数据库的压力

&#x1f389;&#x1f389;欢迎光临&#xff0c;终于等到你啦&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;持续更新的专栏Redis实战与进阶 本专栏讲解Redis从原理到实践 …

【Vue3】走进Pinia,学习Pinia,使用Pinia

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

杰发科技AC7801——读取Flash数据做CRC校验

查看Keil的编译结果发现总共6160个字节。计算结果如下&#xff0c; 代码如下 #include "ac780x_crc.h" #include "ac780x.h" #include "ac780x_debugout.h" #include "string.h" #include "ac780x_eflash.h"#define TestSi…

html5cssjs代码 026 canvas示例

html5&css&js代码 026 canvas示例 一、代码二、解释 这段HTML代码定义了一个页面&#xff0c;其中包含一个容器和一个canvas元素。通过JavaScript代码&#xff0c;使用canvas绘制了一个矩形、一个填充了颜色的矩形、一个文本以及一个圆形。 一、代码 <!DOCTYPE ht…

nodejs基于vue超市信息管理系统flask-django-php

互联网的快速发展&#xff0c;使世界各地的各种组织的管理方式发生了根本性的变化&#xff0c;我国政府、企业等组织在上个世纪90年代就已开始考虑使用互联网来管理信息。由于以前的种种因素&#xff0c;比如网络的普及率不高&#xff0c;用户对它的认知度不够&#xff0c;以及…

Zenlayer如何将万台设备监控从Zabbix迁移到Flashcat

作为全球首家以超连接为核心的云服务商&#xff0c;Zenlayer 致力于将云计算、内容服务和边缘技术融合&#xff0c;为客户提供全面的解决方案。通过构建可靠的网络架构和高效的数据传输&#xff0c;Zenlayer 帮助客户实现更快速、更可靠的连接&#xff0c;提升用户体验和业务效…

局域网内监控别人电脑屏幕

想要在局域网内可以监控他人的屏幕的方法&#xff0c;无疑是使用一款&#xff0c;屏幕监控软件了。 什么是局域网屏幕监控软件&#xff1f; 局域网屏幕监控软件是一种专门用于监控局域网内电脑屏幕活动的软件工具。它通常集成在局域网监控系统中&#xff0c;能够实时捕捉和记…

使用Java JDBC连接数据库

在Java应用程序中&#xff0c;与数据库交互是一个常见的任务。Java数据库连接&#xff08;JDBC&#xff09;是一种用于在Java应用程序和数据库之间建立连接并执行SQL查询的标准API。通过JDBC&#xff0c;您可以轻松地执行各种数据库操作&#xff0c;如插入、更新、删除和查询数…

2024蓝桥杯每日一题(递归)

备战2024年蓝桥杯 -- 每日一题 Python大学A组 试题一&#xff1a;有序分数 试题二&#xff1a;正则问题 试题三&#xff1a;带分数 试题四&#xff1a;约数之和 试题五&#xff1a;分形之城 试题一&#xff1a;有序分数 【题目描述】 【输入格…

AI换脸软件rope最新更新的蓝宝石中文版下载

rope换脸软件蓝宝石版下载地址&#xff1a;点击下载 最近AI软件非常的火爆&#xff0c;今天就给大家带来一个可以AI替换人脸的工具rope&#xff0c;得益于机器学习技术的不断发展&#xff0c;rope经过深度神经网络的无数次迭代优化&#xff0c;最终得出的模型可以自动学习和识…

Linux调试器-gdb的使用

. 个人主页&#xff1a;晓风飞 专栏&#xff1a;数据结构|Linux|C语言 路漫漫其修远兮&#xff0c;吾将上下而求索 文章目录 gdb简单基础指令Linux调试器-gdb使用背景调试准备工作写一个简单的myprocess.c程序makefile程序debug模式运行修改后的Makefile程序 调试(gdb)listruni…

Excalidraw:绘制图形的新利器

title: Excalidraw&#xff1a;绘制图形的新利器 date: 2024/3/19 17:18:08 updated: 2024/3/19 17:18:08 tags: 绘图工具多人协作数据安全简洁设计浏览器访问Docker部署插件扩展 摘要&#xff1a; Excalidraw是一款简洁设计、直观易用的绘图应用&#xff0c;用户可以通过它创…

【IJCAI】CostFormer即插即用的MVS高效代价体聚合Transformer,FaceChain团队出品

一、论文题目&#xff1a; CostFormer: Cost Transformer for Cost Aggregation in Multi-view Stereo&#xff0c;https://arxiv.org/abs/2305.10320 二、论文简介&#xff1a; 多视角立体是三维重建的一种重要实现方式&#xff0c;该方式会从一系列同一场景但不同视角的二维…

解析JS加密解密中的生成器构造

前言 之前JS解密的客户&#xff0c;有一部分代码里是有生成器构造出来代码&#xff0c;一些基础比较薄弱的客户以及技术就看起来比较费劲看不懂了&#xff0c;这里特意写一篇文章为这部分客户服务。尽量言简意赅&#xff0c;以下是示例代码&#xff1a; function YV(YD) {ret…

【动态规划】【 数位dp】2827. 范围中美丽整数的数目

本文涉及知识点 数位dp 动态规划汇总 LeetCode2827. 范围中美丽整数的数目 给你正整数 low &#xff0c;high 和 k 。 如果一个数满足以下两个条件&#xff0c;那么它是 美丽的 &#xff1a; 偶数数位的数目与奇数数位的数目相同。 这个整数可以被 k 整除。 请你返回范围 [l…