1.5 Spring表达式语言(SpEL)
1.5.1 资源注入表达式实战(深度工程应用)
SpEL基础语法全景:
表达式类型:
├─ 字面量:#{'Hello World'}
├─ 属性引用:#{systemProperties['user.timezone']}
├─ 方法调用:#{T(java.lang.Math).random()}
├─ 运算符:
│ ├─ 算术:+,-,*,/,%,^
│ ├─ 关系:eq,ne,lt,gt,le,ge
│ └─ 逻辑:and,or,not
└─ 集合操作:#{users.?[age > 18]}
动态配置注入案例:
@Configuration
public class DynamicConfig {
// 注入操作系统时区
@Value("#{systemProperties['user.timezone']}")
private String systemTimezone;
// 注入随机端口(8000-9000)
@Value("#{T(java.util.concurrent.ThreadLocalRandom).current().nextInt(8000,9000)}")
private int serverPort;
// 注入环境变量
@Value("#{environment['DATABASE_URL'] ?: 'jdbc:mysql://localhost:3306/default'}")
private String databaseUrl;
// 注入集合元素
@Value("#{'${allowed.ips}'.split(',')}")
private List<String> allowedIps;
// 注入Bean属性
@Value("#{dataSource.url}")
private String datasourceUrl;
}
多环境配置表达式方案:
# application-dev.properties
app.notification.enabled=true
app.cache.size=1000
# application-prod.properties
app.notification.enabled=false
app.cache.size=5000
@Service
public class SystemService {
// 根据环境动态启用功能
@Value("#{${app.notification.enabled} ? 'ENABLED' : 'DISABLED'}")
private String notificationStatus;
// 动态计算缓存超时时间
@Value("#{${app.cache.size} * 60 * 1000}")
private long cacheTimeout;
}
1.5.2 条件化配置的表达式技巧(生产级方案)
组合条件表达式实战:
@Configuration
@Conditional(
value = OnRequiredServicesCondition.class
)
public class ServiceConfiguration {
@Bean
@ConditionalOnExpression(
"#{environment.getProperty('app.mode') == 'cluster' && " +
"T(java.net.InetAddress).getLocalHost().hostName.startsWith('node-')}"
)
public ClusterService clusterService() {
return new ClusterServiceImpl();
}
}
public class OnRequiredServicesCondition implements Condition {
@Override
public boolean matches(ConditionContext context,
AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
return env.containsProperty("DB_MASTER_URL") &&
env.containsProperty("CACHE_SERVERS");
}
}
表达式驱动特性开关:
@RestController
public class FeatureController {
// 根据配置动态启用API版本
@GetMapping("/v2/data")
@ConditionalOnExpression("#{environment['app.feature.v2-api'] == 'enabled'}")
public ResponseEntity<?> getDataV2() {
// 新版实现逻辑
}
// 根据日期范围启用功能
@Scheduled(fixedRate = 60000)
@ConditionalOnExpression("#{T(java.time.LocalDate).now().isAfter(T(java.time.LocalDate).parse('2024-01-01'))}")
public void executeYearlyTask() {
// 2024年后启用的任务
}
}
1.5.3 安全权限表达式进阶用法(金融系统案例)
方法级安全控制:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 启用方法级安全注解
}
@Service
public class AccountService {
// 账户必须属于当前用户
@PreAuthorize("#account.owner == authentication.name")
public void updateAccount(Account account) {
// 更新逻辑
}
// 交易金额限制
@PreAuthorize("#amount <= 100000 or hasRole('VIP')")
public void transfer(BigDecimal amount) {
// 转账逻辑
}
// 审计日志访问控制
@PostFilter("filterObject.operator == authentication.name or hasAuthority('AUDIT_READ_ALL')")
public List<AuditLog> getLogs() {
// 查询日志逻辑
}
}
自定义权限表达式:
// 1. 定义根安全对象
public class CustomSecurityExpressionRoot
extends SecurityExpressionRoot {
public CustomSecurityExpressionRoot(Authentication a) {
super(a);
}
public boolean isInDepartment(String deptCode) {
User user = (User) this.authentication.getPrincipal();
return user.getDepartments().contains(deptCode);
}
}
// 2. 注册自定义表达式处理器
public class CustomMethodSecurityExpressionHandler
extends DefaultMethodSecurityExpressionHandler {
@Override
protected SecurityExpressionRoot createSecurityExpressionRoot(
Authentication authentication, MethodInvocation invocation) {
return new CustomSecurityExpressionRoot(authentication);
}
}
// 3. 配置安全策略
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig
extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new CustomMethodSecurityExpressionHandler();
}
}
// 4. 业务层使用
@Service
public class FinanceService {
@PreAuthorize("isInDepartment('FINANCE')")
public void approvePayment() {
// 财务审批逻辑
}
}
1.5.4 SpEL高级特性实战(数据转换与校验)
类型安全转换表达式:
public class DataValidator {
// 强制类型转换
@Value("#{T(java.time.LocalDate).parse('${app.startDate}')}")
private LocalDate startDate;
// 集合元素转换
@Value("#{'${app.ports}'.split(',').?[T(java.lang.Integer).parseInt(#this)]}")
private List<Integer> activePorts;
// 映射转换
@Value("#{${app.ratios}.entrySet().stream().collect(T(java.util.Map).Entry.comparingByValue())}")
private Map<String, Double> sortedRatios;
}
动态校验规则引擎:
public class OrderValidationRules {
// 从配置文件加载规则
@Value("#{'${validation.order.amount}'.split(':')}")
private List<String> amountRules;
public boolean validateAmount(BigDecimal amount) {
String operator = amountRules.get(0);
BigDecimal limit = new BigDecimal(amountRules.get(1));
switch (operator) {
case "gt": return amount.compareTo(limit) > 0;
case "lt": return amount.compareTo(limit) < 0;
default: throw new IllegalArgumentException("无效运算符");
}
}
}
// 配置示例
validation.order.amount=gt:1000