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,一经查实,立即删除!

相关文章

个人工作常用Linux相关总结

bash脚本 更新前端 #!/bin/bash # 定义变量 # 移动zip到相应路径 function move_zip() { if [ -f "$ZIP_FILE" ]; then mv "$ZIP_FILE" "$ZIP_DEST" if [ $? -eq 0 ]; then echo "Zip file moved to $ZIP_DEST" else echo…

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…

飞天使-k8s知识点27-kubernetes温故知新2-deployment

文章目录 RC和RS无状态应用管理 deployment有状态应用statefulSetdaemonSet RC和RS RC不会使用在生产环境 RS 比RC 多了标签选择器 &#xff0c;RS 用deployment管理&#xff0c;用于容器编排无状态应用管理 deployment apiVersion: apps/v1 kind: Deployment metadata:name:…

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 …

jQuery遍历DOM元素

自下而上(获取父节点) 通过jQuery对象可以向上遍历DOM树 parent()返回被选元素的直接父元素。该方法只会向上一级对DOM 树进行遍历。返回要给jQuery对象parents([type]) 返回被选元素的祖先元素可传入字符串过滤类型&#xff0c;返回被选元素中为该类型的祖先元素 parentsUn…

IPD流程学习

集成开发的概念学习&#xff0c; IPD是把产品纳入经营的理念&#xff0c;分为两件事&#xff1a;1是做正确的事&#xff0c;2正确的事情怎么做 1、做正确的事&#xff0c; 市场调研&#xff0c;不是闭门造车需求管理&#xff0c;怎么把客户的需求转变成产品的开发需求&#…

构建Helm chart和chart使用管道与函数简介

目录 一.创建helm chart&#xff08;以nginx为例&#xff09; 1.通过create去创建模板 2.查看模板下的文件 3.用chart模版安装nginx 二.版本更新和回滚问题 1.使用upgrade -f values.yaml或者命令行--set来设置 2.查看历史版本并回滚 三.helm模板内管道和函数 1.defau…

软件工程-第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…

Leetcode 239 滑动窗口最大值

题目信息 LeetoCode地址: . - 力扣&#xff08;LeetCode&#xff09; 题目理解 题意是很好理解的&#xff0c;一个固定长度(k)的滑块从一个数组的左端一步一步向右滑&#xff0c;然后挑出滑块盖住的那些数字中最大的&#xff0c;组成的数组就是结果。 难点在于&#xff0c;…

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;有序分数 【题目描述】 【输入格…