来自Spring @Transactional属性是否适用于私有方法?
使用代理时,应仅将@Transactional注释应用于具有公共可见性的方法.如果使用@Transactional注释对带保护的,私有的或包可见的方法进行注释,则不会引发错误,但带注释的方法不会显示已配置的事务设置.
我可以想出排除private
和package-private
方法的充分理由,但为什么protected
方法不会在事务上表现?以下stacktrace显示公共方法的正确行为(通过接口代理调用):
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_51] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302) ~[spring-aop-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) ~[spring-aop-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281) ~[spring-tx-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) ~[spring-aop-4.2.1.RELEASE.jar:4.2.1.RELEASE] at com.sun.proxy.$Proxy145.improveType(Unknown Source) ~[na:na]
当调用"相同"的受保护方法(通过非接口CGLIB代理)时,我们得到以下内容:
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_51] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302) ~[spring-aop-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) ~[spring-aop-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720) ~[spring-aop-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653) ~[spring-aop-4.2.1.RELEASE.jar:4.2.1.RELEASE] at my.company.webservices.facade.EntityFacade$$EnhancerBySpringCGLIB$$fd77735b.findEntity() ~[spring-core-4.2.1.RELEASE.jar:na]
这显然是一个设计决定(为什么?),但我认为它显然是一个开发人员错误,它无声地失败.
编辑
当使用接口(接口中只有公共方法)时,这显然不是问题,但由于Spring不一定需要通过CGLIB代理对象的接口,因此调用受保护的@Transactional
方法将表现得像公共方法(即通过代理),除了按设计它忽略了事务性.
因为这:
在代理模式(默认设置)下,只会拦截通过代理进入的"外部"方法调用.这意味着'自调用',即目标对象中调用目标对象的其他方法的方法,即使被调用的方法用@Transactional标记,也不会在运行时导致实际的事务!
还有这个:
由于Spring的AOP框架基于代理的特性,受保护的方法根据定义不会被拦截,既不用于JDK代理(这不适用),也不用于CGLIB代理(这在技术上可行,但不建议用于AOP).因此,任何给定的切入点都只能与公共方法匹配!
Spring人员可能希望与JDK代理保持一致.您不希望基于JDK与CGLIB具有不同的代理配置和不同的结果.
其他答案的其他信息。
这是Spring博客的示例图片:
如您所见,代理服务器包裹在实现类(这里是AccountServiceImpl
)周围,代理服务器本身仅实现AccountService
接口中的方法。An Interface
仅提供公共方法(公共合同),因此代理不能围绕受保护的方法包装并提供其在公共方法上提供的交易行为。
如果要使用AspectJ
,可以在同一服务中调用方法,但是我不确定这是否也适用于protected
方法,因为到目前为止我还没有使用过它。