spring – @Transactional – 在后台发生了什么?

我想知道当你使用@Transactional注解一个方法时究竟发生了什么? 当然,我知道Spring将在一个事务中包装这个方法。

但是,我有以下怀疑:

  1. 我听说Spring创build一个代理类 ? 有人可以更深入地解释这一点。 那个代理类实际上驻留了什么? 实际上课会发生什么? 我怎样才能看到Spring创build的代理类
  2. 我还在Spring的文档中看到:

注意:由于这个机制是基于代理的,所以只有通过代理进入的“外部”方法调用才会被拦截 这意味着即使被调用的方法标记为@Transactional ,“自调用”(即调用目标对象的其他方法的目标对象内的方法)也不会导致实际的事务处理。

资料来源: http : //static.springsource.org/spring/docs/2.0.x/reference/transaction.html

为什么只有外部方法调用将在事务中,而不是自调用方法?

这是一个很大的话题。 Spring的参考文档使用了多个章节。 我推荐阅读面向方面编程和事务的部分 ,因为Spring的声明式事务支持在其基础上使用AOP。

但是,在很高的层次上,Spring为类或者成员声明@Transactional的类创build代理。 代理在运行时大部分是不可见的。 它为Spring提供了一种方法,将方法调用之前,之后或周围的行为注入到代理对象中。 事务pipe理只是可以被吸引的行为的一个例子。安全检查是另一个例子。 而且你也可以提供你自己的,如日志logging。 所以当你用@Transactional注解一个方法时,Spring会dynamic地创build一个代理来实现与你注解的类相同的接口。 而当客户端调用你的对象,调用被拦截,并通过代理机制注入的行为。

顺便说一句,EJB中的事务工作也是类似的。

正如你所观察到的那样,代理机制只在来自外部对象的调用时才起作用。 当你在对象内进行内部调用时,你真的是通过绕过代理的“ this ”引用进行调用。 但是,有办法解决这个问题。 我在这个论坛post中解释了一种方法,我在其中使用BeanFactoryPostProcessor在运行时将代理实例注入“自引用”类。 我将这个引用保存到名为“ me ”的成员variables中。 然后,如果我需要进行内部调用,需要改变线程的事务状态,我通过代理来指挥调用(例如“ me.someMethod() ”)。论坛post更详细地解释。 请注意, BeanFactoryPostProcessor代码现在有点不同了,因为它是在Spring 1.x时间框架中写入的。 但希望它给你一个想法。 我有一个我可能提供的更新版本。

当Spring加载你的bean定义,并且被configuration为查找@Transactional注解时,它将在你的实际bean周围创build这些代理对象。 这些代理对象是在运行时自动生成的类的实例。 当一个方法被调用时,这些代理对象的默认行为就是调用“目标”bean(即你的bean)上的同一个方法。

然而,代理也可以被提供拦截器,并且当它们出现时,这些拦截器将在代理调用你的目标bean的方法之前被调用。 对于使用@Transactional注解的目标bean,Spring将创build一个TransactionInterceptor,并将其传递给生成的代理对象。 所以当你从客户端代码中调用方法时,你需要调用代理对象上的方法,它首先调用TransactionInterceptor(开始一个事务),然后调用目标Bean的方法。 当调用完成时,TransactionInterceptor提交/回滚事务。 它对客户端代码透明。

至于“外部方法”的东西,如果你的bean调用它自己的方法之一,那么它不会通过代理来这样做。 请记住,Spring将bean包装在代理中,bean不知道它。 只有来自“外部”的bean的调用通过代理。

这有帮助吗?

作为一个视觉的人,我喜欢用代理模式的顺序图。 如果你不知道如何阅读箭头,我读了第一个这样的: Client执行Proxy.method()

  1. 客户从他的angular度调用目标方法,被代理人静静截获
  2. 如果定义了一个before方面,代理将执行它
  3. 然后,执行实际的方法(目标)
  4. 返回后抛出是在方法返回之后执行的可选方面,或者方法抛出exception
  5. 之后,代理执行后面的方面(如果定义)
  6. 最后代理返回到调用客户端

代理模式序列图 (我被允许发布照片,条件是我提到它的起源。作者:Noel Vaes,网站:www.noelvaes.eu)