0

我已经通过 spring 和 AspectJ 浏览了许多关于 tx 的帖子。下面是总结,说,我有一个服务类和它的接口

interface TestService {
 void methodA();
 void methodB();
}

class TestServiceImpl implements TesService {

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

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

还有我的配置

<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动态代理使用,只会关心@Transactionalon methodA(),不关心@Transactional(propagation=Propagation.NEVER)on methodB()。因此代码通过正确的事务和提交执行。如果我们使用 AspectJ 模式,那么它也会检查@Transactional(propagation=Propagation.NEVER)onmethodB()并抛出异常。

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

  1. Spring 的技术限制是他们无法检查 methodB() 中的注释,尽管它是公开的?但是如果 AspectJ 可以检查它,那为什么不是 Spring 呢?

  2. 他们有意限制了这种 AOP 检查内部方法调用。这种方法调用(目标方法用不同的 transactionPropagation 注释)是否违反了正确的设计方法?

4

3 回答 3

3

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

caller ---> transactionalProxy.methodA() ---> testServiceImpl.methodA()

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

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

caller ---> transactionalProxy.methodA() ---> testServiceImpl.methodA() ---> testServiceImpl.methodB()

而且由于您绕过代理,因此无法应用任何事务方面。

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

我不会说围绕内部方法调用应用方面不是正确的设计。您只需要知道它仅适用于字节码检测。

于 2012-08-03T07:06:53.423 回答
1

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

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(){}

}
于 2014-08-12T13:24:03.893 回答
0

这里的想法是,最外层的方法知道什么对整个事务最有利。但是,正如您所注意到的,存在一些极端情况。

解决方法:将方法的实现移动到第二个 bean 并将该 bean 注入到您的TestServiceImpl. 由于您将获得代理注入,因此所有方法调用都会注意注释。

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

methodX() {
     ...code before...
     methodB();
     ...code after...
}

您可以使用回调:

methodX() {
     Callable<Void> callback = new Callable<Void>() {
         Void call() {
              realImpl.methodB();
         }
     }
     realImpl.methodX(callback);
}

在你的内心豆中:

void methodX(Callable<Void> callback) {
     ...code before...
     callback();
     ...code after...
}
于 2012-08-03T08:21:20.147 回答