首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring 3事务框架背后的设计原则

Spring 3事务框架背后的设计原则
EN

Stack Overflow用户
提问于 2012-08-03 05:37:55
回答 3查看 202关注 0票数 0

我已经看过很多关于tx的文章,包括spring和AspectJ。下面是总结,比如说,我有一个服务类及其接口。

代码语言:javascript
复制
interface TestService {
 void methodA();
 void methodB();
}

class TestServiceImpl implements TesService {

   @Transactional
   void methodA() {
      methodB();
   }

   @Transactional(propagation=Propagation.NEVER)
   void methodB(){}
}

还有我的配置

代码语言:javascript
复制
<tx:annotation-driven transaction-manager="jpaTxManager"/>

<bean id="jpaTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"><ref bean="entityManagerFactory"/></property>
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>

<bean id="testService" class="com.motherframework.plugin.test.service.TestServiceImpl">
     <property name="testDAO" ref="testDAO"/>
</bean>

我从某个客户端类调用testService.methodA()。根据spring的JDK动态代理使用情况,它只关心methodA()上的methodA(),而不关心methodB()上的@Transactional(propagation=Propagation.NEVER)。因此,代码以正确的事务执行并提交。如果我们使用AspectJ模式,那么它还将检查methodB()上的@Transactional(propagation=Propagation.NEVER)并引发异常。

现在我的问题是,为什么这个限制是由Spring强加的?现在有两种设计弹簧的可能性,

  1. 虽然methodB()是公开的,但它们不能检查注释,这是spring的一个技术限制。但是如果AspectJ可以检查它,那为什么不检查Spring呢?
  2. 他们有意地限制了AOP对内部方法调用的检查。这种方法调用(使用不同的transactionPropagation注释目标方法)是否有悖于正确的设计方法?
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-08-03 07:06:53

是的,这是技术上的限制。当您不使用AspectJ时,事务方面是通过在实际bean类实例周围返回代理并将该代理返回/注入到其他bean来实现的。因此,当您调用testService.methodA()时,会发生以下情况(基本上):

代码语言:javascript
复制
caller ---> transactionalProxy.methodA() ---> testServiceImpl.methodA()

代理将围绕对testServiceImpl.methodA()的调用应用事务方面:它在之前启动事务,然后提交/回滚事务。

如果从this.methodB()调用methodA(),则会发生以下情况:

代码语言:javascript
复制
caller ---> transactionalProxy.methodA() ---> testServiceImpl.methodA() ---> testServiceImpl.methodB()

而且,由于您绕过了代理,所以不能应用事务方面。

AspectJ是不同的,因为它转换TestServiceImpl的字节代码,以应用围绕各种方法调用的方面。

我不认为围绕内部方法调用应用方面是不恰当的设计。您只需注意,它只适用于字节码检测。

票数 3
EN

Stack Overflow用户

发布于 2014-08-12 13:24:03

这是一个技术限制(正如其他人所回答的)。如果您想让Spring检查这个,您可以这样修改您的服务:

代码语言:javascript
复制
class TestServiceImpl implements TesService {

   TesService thiz; // setter left outside, assumed to be injected by Spring

   @Transactional
   void methodA() {
      thiz.methodB();
   }

   @Transactional(propagation=Propagation.NEVER)
      void methodB(){}

}
票数 1
EN

Stack Overflow用户

发布于 2012-08-03 08:21:20

这里的想法是,最外层的方法知道什么是对整个事务最好的。但是,正如你注意到的,这里有一些角落的案件。

解决办法:将方法的实现移到第二个bean中,并将该bean注入TestServiceImpl。因为您将被注入代理,所以所有方法调用都会注意到注释。

您需要拆分一些方法。如果你有这种情况:

代码语言:javascript
复制
methodX() {
     ...code before...
     methodB();
     ...code after...
}

您可以使用回调:

代码语言:javascript
复制
methodX() {
     Callable<Void> callback = new Callable<Void>() {
         Void call() {
              realImpl.methodB();
         }
     }
     realImpl.methodX(callback);
}

在你内心的豆子里:

代码语言:javascript
复制
void methodX(Callable<Void> callback) {
     ...code before...
     callback();
     ...code after...
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11789857

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档