构造函数 (Constructors)
你可以使用 new 运算符来调用构造函数。除了位于 java.lang 包(如 Integer、Float、String 等)中的类型外,你应该对所有其他类型使用全限定类名。SpEL 也支持可变参数 (Varargs)。
以下示例演示了如何使用 new 运算符调用构造函数:
java
// 创建一个新的 Inventor 实例
Inventor einstein = parser.parseExpression(
"new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")
.getValue(Inventor.class);
// 在 List 的 add() 方法调用中创建一个新的 Inventor 实例
parser.parseExpression(
"Members.add(new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German'))")
.getValue(societyContext);kotlin
// 创建一个新的 Inventor 实例
val einstein = parser.parseExpression(
"new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")
.getValue(Inventor::class.java)
// 在 List 的 add() 方法调用中创建一个新的 Inventor 实例
parser.parseExpression(
"Members.add(new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German'))")
.getValue(societyContext)补充教学
1. 构造函数 vs Bean 引用
这是开发者最容易混淆的地方:
new com.example.MyBean():这将绕过 Spring 容器,直接在 JVM 堆内存中创建一个普通对象。该对象不具备 Spring 的任何特性(如@Autowired会失效,没有任何切面增强)。@myBean:这是引用由 Spring 容器管理的 Bean。- 建议:除非你需要创建一个临时的、纯碎的数据承载对象(如 DTO),否则应优先使用 Bean 引用。
2. 安全性警告:SpEL 注入
在表达式中使用 new 是非常强大的功能,但也是最危险的。
- 风险:如果 SpEL 表达式的一部分来自于用户输入,攻击者可能会构造类似
new java.lang.ProcessBuilder('calc.exe').start()的表达式来执行任意命令。 - 防御:在处理不可信输入时,务必使用
SimpleEvaluationContext。默认情况下,SimpleEvaluationContext不支持new运算符,从而切断了此类攻击路径。
3. 应用场景:动态数据转换
构造函数在 SpEL 中最实用的场景通常是在 集合投影 或 报表导出 中将原始数据转换为视图对象 (VO):
java
// 假设从数据库查出一组原始数据,直接在 SpEL 中转换为特定的简单的 DTO
@Value("#{allUsers.![new com.example.UserVo(username, email)]}")
private List<UserVo> userVos;4. 关于类名简写的再次提醒
类似于 T() 运算符,只有 java.lang 包下的类可以简写。
- 正确:
new String('test') - 错误:
new Date()(必须写成new java.util.Date()) - 如果你觉得全限定名太长,可以参考类型章节中的
TypeLocator注册技巧来简化类名。