it编程 > 编程语言 > Java

Spring注入值中含有特殊符号的处理详解

15人参与 2026-09-16 Java

一、为什么特殊符号会导致问题?

spring 在注入值时,会经过多层解析:

  1. xml 解析<>& 等是 xml 语法字符
  2. 属性占位符解析${} 是占位符语法,: 是默认值分隔符
  3. spel 表达式解析#{} 是表达式语法
  4. 类型转换, 可能被当作集合分隔符
  5. yaml 解析:#{} 等是 yaml 语法字符

每一层都可能把特殊符号“吃掉”或误解析,导致注入结果与预期不符。

二、xml 配置中的特殊符号

2.1 xml 转义字符

xml 中有五个预定义实体,必须转义:

特殊符号转义写法说明
<&lt;小于号
>&gt;大于号
&&amp;和号
"&quot;双引号
'&apos;单引号
<!-- ❌ 错误:& 未转义 -->
<property name="url" value="jdbc:mysql://localhost:3306/db?usessl=false&servertimezone=utc"/>
<!-- ✅ 正确:& 转义为 & -->
<property name="url" value="jdbc:mysql://localhost:3306/db?usessl=false&servertimezone=utc"/>

2.2 使用 cdata 避免转义

如果值中包含大量特殊字符,用 <![cdata[...]]> 包裹:

<property name="sql">
    <value><![cdata[
        select * from user where age > 18 and name != 'test'
    ]]></value>
</property>

cdata 中的内容不会被 xml 解析器解析,><& 都可以直接写。

2.3 值中含双引号或单引号

<!-- 值中含双引号:外层用单引号 -->
<property name="message" value='he said "hello"'/>
<!-- 值中含单引号:外层用双引号 -->
<property name="message" value="it's a test"/>

三、@value 中的特殊符号

3.1 值中含$符号

$@value 中用于 ${} 占位符。如果值本身包含 $,需要转义。

// 配置文件:app.price=$100
// ❌ 错误:spring 会把 $100 当作占位符
@value("${app.price}")

// ✅ 正确:配置文件中转义,或用默认值

在 properties 文件中:

app.price=$100

@value 中,$ 本身不需要转义,但如果配置文件中写 ${app.price} 这种形式,$ 会被解析:

// 如果配置值就是字面量 "$100"
@value("${app.price}")
private string price;  // 注入 "$100",正常

如果值中包含 ${ 这样的组合,需要用 \ 转义:

@value("${app.template:\\${name}}")
private string template;  // 注入 "${name}"

3.2 值中含#符号

#@value 中用于 #{} spel 表达式。如果值本身包含 #,需要处理。

app:
  color: "#ff0000"
// ❌ 错误:spring 会把 #ff0000 当作 spel
@value("${app.color}")

// ✅ 正确:配置值中的 # 本身不会触发 spel,因为 # 只在 #{} 中才触发
@value("${app.color}")
private string color;  // 注入 "#ff0000",正常

只有当 # 后面紧跟 { 时才会触发 spel 解析。单独的 # 没问题。

3.3 值中含:符号

:@value 中用于分隔配置键和默认值。如果配置值本身包含 :,需要注意。

// 配置文件:app.url=jdbc:mysql://localhost:3306/db
// ✅ 正常,因为 : 在配置值中,不在占位符语法中
@value("${app.url}")
private string url;  // 注入 "jdbc:mysql://localhost:3306/db"

但如果写默认值时:

// ❌ 错误:spring 会把 jdbc 当作默认值,后面的内容被忽略
@value("${app.url:jdbc:mysql://localhost:3306/db}")
private string url;

// ✅ 正确:用 spel 或拆分配置
@value("${app.url:}")
private string url;

3.4 值中含逗号,

逗号在集合注入中会被当作分隔符。

app:
  servers: server1,server2,server3
@value("${app.servers}")
private list<string> servers;  // 自动拆分为 3 个元素

如果值本身包含逗号:

app:
  message: "hello, world"
// ❌ 错误:会被拆分成 "hello" 和 " world" 两个元素
@value("${app.message}")
private list<string> messages;

// ✅ 正确:用 string 接收
@value("${app.message}")
private string message;

3.5 值中含反斜杠\

app:
  path: "c:\\users\\admin"
@value("${app.path}")
private string path;  // 注入 "c:\users\admin"

在 yaml 中,双引号内的 \ 是转义字符,需要写 \\。单引号内不转义:

app:
  path: 'c:\users\admin'  # 单引号内原样输出

四、yaml 中的特殊符号

4.1 :的处理

yaml 中 : 是键值分隔符。如果值中含 :,需要加引号。

# ❌ 错误:值中的 : 可能被解析为新的键值对
app:
  url: jdbc:mysql://localhost:3306/db
# ✅ 正确:加引号
app:
  url: "jdbc:mysql://localhost:3306/db"

4.2 #的处理

# 在 yaml 中是注释符。如果值中含 #,需要加引号。

# ❌ 错误:# 后面被当作注释
app:
  color: #ff0000
# ✅ 正确:加引号
app:
  color: "#ff0000"

4.3 {和}的处理

{} 在 yaml 中表示内联 map。如果值中含 {},需要加引号。

# ❌ 错误:被解析为 map
app:
  template: {name}
# ✅ 正确:加引号
app:
  template: "{name}"

4.4 [和]的处理

[] 在 yaml 中表示列表。如果值中含 [],需要加引号。

# ❌ 错误:被解析为列表
app:
  pattern: [a-z]+
# ✅ 正确:加引号
app:
  pattern: "[a-z]+"

4.5 &*!|>的处理

这些都是 yaml 的特殊字符,值中含这些字符时建议加引号。

app:
  expr: "a & b"
  alias: "*ref"
  tag: "!important"
  multi: "|line"
  folded: ">text"

五、properties 文件中的特殊符号

5.1 \转义

properties 文件中,\ 是转义字符:

# \ 需要写成 \\
app.path=c:\\users\\admin
# : 和 = 在键中需要转义
app\:key=value
# 空格在值末尾需要转义
app.name=hello\ 

5.2 unicode 转义

properties 文件默认使用 iso-8859-1 编码,中文需要转义:

app.name=\u5f20\u4e09

或者使用 utf-8 编码加载(spring boot 默认支持)。

5.3 $的处理

app.price=$100

@value("${app.price}") 中,$100 会正常注入,因为 $ 单独出现不会触发占位符解析。

六、spel 表达式中的特殊符号

6.1 字符串中的单引号

spel 中字符串用单引号表示。如果字符串本身含单引号,需要转义:

@value("#{'it\\'s a test'}")
private string message;  // "it's a test"

6.2 字符串中的双引号

@value("#{'he said \"hello\"'}")
private string message;

6.3 值的拼接

@value("#{'${app.name}' + '-' + '${app.version}'}")
private string fullname;

七、完整示例:数据库连接 url

数据库 url 是典型的含特殊符号的配置,包含 :/?&= 等。

yaml 写法:

spring:
  datasource:
    url: "jdbc:mysql://localhost:3306/mydb?usessl=false&servertimezone=asia/shanghai&characterencoding=utf8"
    username: root
    password: "p@ssw0rd#123"

properties 写法:

spring.datasource.url=jdbc:mysql://localhost:3306/mydb?usessl=false&servertimezone=asia/shanghai&characterencoding=utf8
spring.datasource.username=root
spring.datasource.password=p@ssw0rd#123

properties 文件中 &#@ 不需要转义(# 在行首才是注释)。

xml 写法:

<bean id="datasource" class="com.zaxxer.hikari.hikaridatasource">
    <property name="jdbcurl" 
              value="jdbc:mysql://localhost:3306/mydb?usessl=false&servertimezone=asia/shanghai&characterencoding=utf8"/>
    <property name="username" value="root"/>
    <property name="password" value="p@ssw0rd#123"/>
</bean>

xml 中 & 必须转义为 &amp;

八、各场景特殊符号处理速查表

特殊符号xmlyamlproperties@valuespel
&&amp;建议加引号直接写直接写直接写
<&lt;建议加引号直接写直接写直接写
>&gt;建议加引号直接写直接写直接写
"&quot; 或外层用单引号外层用单引号直接写直接写\"
'&apos; 或外层用双引号外层用双引号直接写直接写\'
:直接写建议加引号键中需转义默认值分隔符直接写
#直接写必须加引号行首是注释直接写#{} 触发表达式
$直接写直接写直接写${} 触发占位符直接写
{ }直接写必须加引号直接写${} 语法#{} 语法
[ ]直接写必须加引号直接写直接写直接写
,直接写直接写直接写集合分隔符直接写
\直接写双引号内 \\\\转义符\\
%直接写直接写直接写直接写取模运算符

九、最佳实践

yaml 中值一律加引号。 这是最省心的做法。加引号后,yaml 不再解析值中的特殊字符,原样传递。

app:
  url: "jdbc:mysql://localhost:3306/db?usessl=false&servertimezone=utc"
  password: "p@ssw0rd#123"
  pattern: "[a-z]+"
  template: "{name}"

xml 中注意五个预定义实体。 &<>"' 必须转义,或用 cdata 包裹。

@value 中的默认值含 : 时,用 spel 处理。 因为 : 是默认值分隔符,直接写会有歧义。

// ❌ 有歧义
@value("${app.url:jdbc:mysql://localhost/db}")

// ✅ 用 spel
@value("#{'${app.url:}' ?: 'jdbc:mysql://localhost/db'}")

密码等敏感值始终加引号。 密码中可能包含 #@$! 等字符,加引号可以避免解析问题。

配置值中的逗号用 string 接收。 如果需要保持逗号不被拆分,用 string 类型接收,再手动处理。

十、总结

场景核心问题解决方案
xml 中的 &<>xml 语法冲突转义为 &amp;&lt;&gt; 或用 cdata
yaml 中的 :#{}[]yaml 语法冲突值加引号
properties 中的 \转义字符\\
@value 默认值中的 :分隔符冲突用 spel 表达式处理
@value 中的 $#占位符/spel 语法单独出现不触发,${#{ 需转义
集合注入中的 ,被当作分隔符改用 string 接收后手动拆分
spel 中的引号字符串边界冲突\'\" 转义

处理特殊符号的核心原则是:知道每一层解析器的语法规则,在对应层级做正确的转义或加引号。yaml 中加引号是最简单有效的做法;xml 中注意预定义实体和 cdata;@value 中注意 ${}#{}: 的语法含义。理解这些规则,就能避免绝大多数注入异常。

以上就是spring注入值中含有特殊符号的处理详解的详细内容,更多关于spring注入值中含有特殊符号的资料请关注代码网其它相关文章!

(0)

您想发表意见!!点此发布评论

推荐阅读

SpringBoot结合jasypt进行配置文件加解密的方法步骤

09-16

SpringBoot 3升级后aj-captcha行为验证码底图加载失效的排查过程与解决方案

09-16

Java中ArrayList动态数组的实现与性能优化指南

09-16

Spring AOP 接口日志脱敏:控制打印内容,避免敏感字段外泄

09-16

Java 对象拷贝避坑:如何避免空值覆盖与数据误改

09-16

Spring 级联属性赋值最佳实践

09-16

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论