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]}
动态配置注入案例:
java">@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
java">@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 条件化配置的表达式技巧(生产级方案)
组合条件表达式实战:
java">@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 {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Environment env = context.getEnvironment();return env.containsProperty("DB_MASTER_URL") &&env.containsProperty("CACHE_SERVERS");}
}
表达式驱动特性开关:
java">@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 安全权限表达式进阶用法(金融系统案例)
方法级安全控制:
java">@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() {// 查询日志逻辑}
}
自定义权限表达式:
java">// 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 {@Overrideprotected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {return new CustomSecurityExpressionRoot(authentication);}
}// 3. 配置安全策略
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {@Overrideprotected MethodSecurityExpressionHandler createExpressionHandler() {return new CustomMethodSecurityExpressionHandler();}
}// 4. 业务层使用
@Service
public class FinanceService {@PreAuthorize("isInDepartment('FINANCE')")public void approvePayment() {// 财务审批逻辑}
}
1.5.4 SpEL高级特性实战(数据转换与校验)
类型安全转换表达式:
java">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;
}
动态校验规则引擎:
java">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