为什么Spring的@Transactional不能用于受保护的方法? [英] Why doesn't Spring's @Transactional work on protected methods?

查看:146
本文介绍了为什么Spring的@Transactional不能用于受保护的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自 Spring @Transactional属性是否适用于私有方法?


使用代理时,应将@Transactional注释
仅应用于具有公共可见性的方法。如果使用@Transactional注释对
私有或包可见方法进行注释,
不会引发错误,但带注释的方法不会显示
配置的事务设置。

When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings.

我可以想出排除 private 包的充分理由-private 方法,但为什么 protected 方法不会以事务方式运行?以下stacktrace显示公共方法的正确行为(通过接口代理调用):

I can think of good reasons to exclude private and package-private methods, but why won't protected methods behave transactionally? The following stacktrace displays the correct behaviour for a public method (called through an interface proxy):

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代理)时,我们得到以下内容:

When calling an "identical" protected method (through a non-interface CGLIB proxy), we get the following:

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(<generated>) ~[spring-core-4.2.1.RELEASE.jar:na]

这显然是一个设计决定(为什么?),但我认为当它明显是开发人员错误时,它会无声地失败。

This is apparently a design decision (why?), but I consider it rather questionable that it fails silently, when it's clearly a developer error.

编辑
这显然不是当使用接口(仅接口中的公共方法)时出现问题,但由于Spring不一定需要通过CGLIB代理对象的接口,因此调用受保护的 @Transactional 方法将表现出来就像一个公共方法(即通过代理调用),除了按设计它忽略了事务性。

Edit This is obviously not an issue when using interfaces (only public methods in interfaces), but as Spring doesn't necessarily need an interface to proxy an object through CGLIB, calling a protected @Transactional method will behave just like a public method (i.e. called through a proxy), except that by design it ignores the transactionality.

推荐答案

因为这个:


在代理模式(默认设置)下,只会拦截通过代理进入的外部方法调用。这意味着'自调用',即目标对象中调用目标对象的其他方法的方法,即使被调用的方法用@Transactional标记,也不会在运行时导致实际的事务!

In proxy mode (which is the default), only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with @Transactional!

这个:


由于基于代理Spring的AOP框架的性质,受保护的方法根据定义不被截获,既不用于JDK代理(这不适用),也不用于CGLIB代理(这在技术上是可行的,但不建议用于AOP)。因此,任何给定的切入点都只能与公共方法匹配!

Due to the proxy-based nature of Spring's AOP framework, protected methods are by definition not intercepted, neither for JDK proxies (where this isn't applicable) nor for CGLIB proxies (where this is technically possible but not recommendable for AOP purposes). As a consequence, any given pointcut will be matched against public methods only!

Spring人员可能希望与JDK代理保持一致。您不希望基于JDK与CGLIB具有不同的代理配置和不同的结果。

The Spring guys would probably want to keep consistency with JDK proxies. You wouldn't want to have different proxy configuration and different results based on JDK versus CGLIB.

这篇关于为什么Spring的@Transactional不能用于受保护的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆