春天 - @Transactional - 背景中发生了什么?

我想知道当你用?当然,我知道Spring会将该方法包装在事务中。@Transactional

但是,我有以下疑问:

  1. 我听说Spring创建了一个代理类?有人可以更深入地解释这一点吗?该代理类中实际驻留的内容是什么?实际类会发生什么情况?我怎么能看到Spring创建的代理类
  2. 我还在春季文档中读到:

注意:由于此机制基于代理,因此只有通过代理传入的“外部”方法调用才会被拦截。这意味着“自调用”,即目标对象中的方法调用目标对象的其他方法,即使调用的方法被标记为@Transactional,也不会在运行时导致实际的事务!

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

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


答案 1

这是一个大话题。春季参考文档用了多章来介绍它。我建议阅读有关面向方面的编程事务的内容,因为Spring的声明性事务支持在其基础中使用AOP。

但是在非常高的级别上,Spring为在类本身或成员上声明的类创建代理。代理在运行时大多是不可见的。它为Spring提供了一种将方法调用之前,之后或周围的行为注入到被代理的对象中的方法。事务管理只是可以挂钩的行为的一个例子。安全检查是另一回事。您也可以为日志记录等内容提供自己的内容。因此,当您使用 对方法进行注释时,Spring 会动态创建一个代理,该代理实现与要注释的类相同的接口。当客户端调用您的对象时,调用将被拦截,并通过代理机制注入行为。@Transactional@Transactional

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

正如您所观察到的,代理机制仅在调用从某个外部对象传入时才有效。当您在对象中进行内部调用时,您实际上是通过绕过代理的引用进行调用。但是,有一些方法可以解决这个问题。我在这篇论坛文章中解释了一种方法,其中我使用a在运行时将代理的实例注入“自引用”类中。我将此引用保存到一个名为 的成员变量 。然后,如果我需要进行内部调用,需要更改线程的事务状态,我会通过代理定向调用(例如.论坛帖子更详细地解释了。thisBeanFactoryPostProcessormeme.someMethod()

请注意,现在的代码会有所不同,因为它是在Spring 1.x时间帧中编写的。但希望它能给你一个想法。我有一个更新的版本,我可能会提供。BeanFactoryPostProcessor


答案 2

当Spring加载您的bean定义,并且已被配置为查找注释时,它将围绕您的实际Bean创建这些代理对象。这些代理对象是在运行时自动生成的类的实例。当调用方法时,这些代理对象的默认行为只是在“目标”Bean(即您的bean)上调用相同的方法。@Transactional

但是,代理也可以提供拦截器,当存在这些拦截器时,代理将在调用目标Bean的方法之前调用这些拦截器。对于标注了 的目标 Bean,Spring 将创建一个 ,并将其传递给生成的代理对象。因此,当您从客户端代码调用该方法时,您正在代理对象上调用该方法,该代理对象首先调用(开始事务),然后调用目标Bean上的方法。调用完成后,提交/回滚事务。它对客户端代码是透明的。@TransactionalTransactionInterceptorTransactionInterceptorTransactionInterceptor

至于“外部方法”的事情,如果你的bean调用了它自己的方法之一,那么它就不会通过代理这样做。请记住,Spring将你的豆子包裹在代理中,你的豆子对此一无所知。只有来自“外部”的调用才会通过代理。

这有帮助吗?


推荐