当前位置: 首页 > 面试题库 >

Spring的@Transactional为什么不能在受保护的方法上工作?

卞经业
2023-03-14
问题内容

从上一个私有方法春天在什么@Transactional属性的工作?

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

我可以想到排除privatepackage- private方法的充分理由,但是为什么protected方法不能在事务上表现呢?以下堆栈跟踪显示了公共方法的正确行为(通过接口代理调用):

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

这显然是一个设计决定(为什么?),但我认为这很可疑,因为它显然是开发人员错误,但它会在无提示的情况下失败。

编辑
使用接口(仅接口中的公共方法)时,这显然不是问题,但是由于Spring不一定需要接口来通过CGLIB代理对象,因此调用受保护的@Transactional方法的行为就像公共方法(即,通过代理),只是
设计 上忽略了交易性。


问题答案:

因为这:

在代理模式下(默认),将仅拦截通过代理传入的“外部”方法html" target="_blank">调用。这意味着即使调用的方法标记有@Transactional,“自调用”(即目标对象中的方法调用目标对象的其他方法)也不会在运行时导致实际事务!

还有这个:

由于Spring的AOP框架基于代理的性质,因此,无论是JDK代理(不适用)还是CGLIB代理(在技术上可行但不建议用于AOP的目的),定义上都不会拦截受保护的方法。结果,任何给定的切入点将仅与公共方法匹配!

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



 类似资料:
  • 我可以想出排除和方法的充分理由,但为什么方法不会以事务性方式运行呢?以下stacktrace显示了公共方法(通过接口代理调用)的正确行为: 当调用一个“完全相同”的受保护方法(通过非接口CGLIB代理)时,我们得到如下结果: 这显然是一个设计决定(为什么?),但我认为它很值得怀疑的是,当它显然是开发人员的错误时,它却无声无息地失败了。 编辑这显然不是使用接口(只是接口中的公共方法)时的问题,但由于

  • 我熟悉。正如我在spring文档http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/aop.html中看到的,基于代理的概念。 在8.2.3.1支持的切入点指定器部分中,我发现了下面的注释 由于Spring的AOP框架的基于代理的性质,受保护的方法根据定义是不被拦截的,对于JDK代理(如果这不适用)和CGL

  • 问题内容: 在Java中,为什么不能在接口中使用受保护的方法? 由于根据Java规范 受保护的访问(由关键字protected表示)-同一包中任何类型以及任何包中的子类均可访问的字段或方法。 如果我必须使用该接口,那么我将实现它并覆盖方法。因此,如果我要实现类可以访问这些方法的位置,因为该方法可以在任何包中访问。那么,将方法声明为Interface中的保护有什么害处? 问题答案: 受保护的方法旨在

  • 问题内容: 出于好奇, 为什么将方法的访问修饰符设置为。为什么不能呢?有人可以向我解释这背后的任何具体原因吗? 另外,我知道该方法仅被调用一次。如果我在程序内部两次调用它,会发生什么情况?垃圾收集器会再次调用吗? 问题答案: 我用另一个问题回答您的问题: 为什么方法不应该受到保护? 通常,您应该尝试使事物尽可能私密。这就是封装的全部意义所在。否则,您 什么都 可以做。不能(因为派生类应该能够访问它

  • 问题内容: 有谁知道, 为什么 AbstractList (以及ArrayList)中的removeRange方法是?它看起来像是一个定义明确且有用的操作,但是仍然要使用它,我们不得不对List实现进行子类化。 有一些隐藏的理由吗?对我来说似乎莫名其妙。 问题答案: 是的,因为这不是您从外部代码中删除范围的方式。相反,请执行以下操作: 这实际上是在幕后。† OP询问为什么不属于公共API。原因在《

  • 问题内容: 定义为的受保护的具体原因是什么? 问题答案: 克隆受到保护的事实非常令人怀疑-事实是该clone方法未在Cloneable接口中声明。 它使该方法对于获取数据副本非常无用,因为你不能说: 我认为,Cloneable现在的设计在很大程度上被认为是一个错误(以下引用)。我通常希望能够实现接口的实现,Cloneable但不一定要实现接口Cloneable(类似于的使用Serializable