如何使用Spring EL设置tx:method的timeout实现可配置事务超时
问题说明
需要基于Spring Profiles实现可配置的事务超时,原本尝试通过Spring EL设置tx:advice/tx:attributes/tx:method节点的timeout属性。相同的SpEL写法在默认beans命名空间的标签属性上可以正常运行,但在tx命名空间下配置无法生效,触发如下报错:
Line 21 in XML document from class path resource [spring-core-main.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 21; columnNumber: 148; cvc-datatype-valid.1.2.1: '#{transactionTimeoutSeconds}' is not a valid value for 'integer'.
触发问题的原有配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <bean id="transactionTimeoutSeconds" class="java.lang.Integer"> <constructor-arg value="30" /> </bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" timeout="#{transactionTimeoutSeconds}" /> </tx:attributes> </tx:advice> </beans>
问题原因
tx:method的timeout属性在Spring tx命名空间的XSD定义中为整数类型,XML解析阶段的schema校验会先于SpEL表达式解析执行,直接把#{transactionTimeoutSeconds}字符串当做整数校验,自然会抛出类型不匹配错误,且tx命名空间的解析器本身也没有对该属性做SpEL解析的逻辑。
可行实现方案
可以通过纯XML配置实现需求,不需要切换为Java配置类。核心思路是绕过tx:advice命名空间简写,手动装配其底层依赖的TransactionInterceptor Bean,普通Bean的属性注入支持SpEL解析,也不会触发tx命名空间的schema校验问题。
具体配置示例:
<!-- 可根据不同Spring Profile定义不同值的超时Bean,实现环境差异化配置 --> <bean id="transactionTimeoutSeconds" class="java.lang.Integer"> <constructor-arg value="30" /> </bean> <!-- 手动定义事务拦截器,替代<tx:advice>标签 --> <bean id="txAdvice" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <props> <!-- 事务属性规则:timeout_后接超时秒数,和tx:method的timeout属性效果完全一致,支持SpEL --> <prop key="*">timeout_#{transactionTimeoutSeconds}</prop> </props> </property> </bean> <!-- 原有AOP切面配置无需修改,正常引用txAdvice即可 --> <aop:config> <aop:pointcut id="serviceOperationPointcut" expression="execution(* com.yourpackage.service..*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperationPointcut"/> </aop:config>
如果不想使用SpEL,也可以配合属性占位符${}实现:将不同环境的超时值配置到对应profile加载的properties文件中,prop里直接写timeout_${transaction.timeout.seconds}即可,效果一致。
不要尝试通过关闭XML schema校验的方式解决问题,会丢失全量XML配置的合法性检查,大幅提升配置出错的概率。
内容的提问来源于stack exchange,提问作者Géza
相关产品推荐
相关产品推荐

