Java Spring-@Transactional-后台会发生什么?
我想知道当您使用Java Spring-@Transactional-后台会发生什么?,java,spring,spring-aop,spring-jdbc,transactional,Java,Spring,Spring Aop,Spring Jdbc,Transactional,我想知道当您使用@Transactional注释一个方法时,实际会发生什么? 当然,我知道Spring将在事务中封装该方法 但是,我有以下疑问: 我听说Spring创建了一个代理类?有人能更深入地解释一下吗该代理类中实际驻留的是什么?实际的类发生了什么?我如何才能看到Spring创建的代理类 我还在Spring文档中读到: 注意:由于此机制基于代理,只有通过代理传入的“外部”方法调用才会被拦截。这意味着“自调用”,即目标对象内调用目标对象其他方法的方法,即使调用的方法标记为@Transactio
@Transactional
注释一个方法时,实际会发生什么?
当然,我知道Spring将在事务中封装该方法
但是,我有以下疑问:
@Transactional
,在运行时也不会导致实际事务
资料来源:
为什么只有外部方法调用在事务下,而不是自调用方法下?这是一个大话题。Spring参考文档有多个章节专门介绍它。我建议阅读上面的文章,因为Spring的声明性事务支持在其基础上使用AOP。 但在非常高的级别上,Spring为类创建代理,这些类在类本身或成员上声明
@Transactional
。代理在运行时基本不可见。它为Spring提供了一种将方法调用之前、之后或前后的行为注入被代理对象的方法。事务管理只是可以连接的行为的一个例子。安全检查是另一个问题。您也可以提供自己的日志记录。因此,当您使用@Transactional
注释一个方法时,Spring会动态创建一个代理,该代理实现与您正在注释的类相同的接口。当客户机对您的对象进行调用时,会截获调用,并通过代理机制注入行为
顺便说一句,EJB中的事务工作方式类似
正如您所观察到的,通过,代理机制仅在从某个外部对象传入调用时才起作用。在对象内进行内部调用时,实际上是通过this
引用进行调用,该引用绕过了代理。然而,有一些方法可以解决这个问题。我解释了一种方法,其中我使用BeanFactoryPostProcessor
在运行时将代理实例注入到“自引用”类中。我将此引用保存到名为me
的成员变量。然后,如果我需要进行需要更改线程事务状态的内部调用,我会通过代理(例如,me.someMethod()
)引导调用,论坛帖子对此进行了更详细的解释
请注意,
BeanFactoryPostProcessor
代码现在会有点不同,因为它是在Spring1.x时间框架中编写的。但希望它能给你一个想法。我有一个更新版本,我可能可以提供。当Spring加载bean定义,并配置为查找@Transactional
注释时,它将围绕实际bean创建这些代理对象。这些代理对象是在运行时自动生成的类的实例。调用方法时,这些代理对象的默认行为只是在“目标”bean(即您的bean)上调用相同的方法
但是,代理也可以提供拦截器,当存在拦截器时,这些拦截器将在代理调用目标bean的方法之前由代理调用。对于使用@Transactional
注释的目标bean,Spring将创建一个TransactionInterceptor
,并将其传递给生成的代理对象。因此,当您从客户机代码调用该方法时,您是在代理对象上调用该方法,该代理对象首先调用TransactionInterceptor
(它开始一个事务),然后它又调用目标bean上的方法。调用完成后,TransactionInterceptor
提交/回滚事务。它对客户端代码是透明的
至于“外部方法”这件事,如果您的bean调用它自己的方法之一,那么它将不会通过代理这样做。记住,Spring将您的bean包装在代理中,您的bean对此一无所知。只有来自bean“外部”的调用才能通过代理
这有帮助吗?作为一个视觉人,我喜欢用代理模式的序列图来衡量。如果您不知道如何读取箭头,我会这样读取第一个箭头:
Client
执行Proxy.method()
(我被允许发布这张照片,条件是我提到了它的起源。作者:Noel Vaes,网站:)最简单的答案是: 无论在哪种方法上声明
@Transactional
,事务边界都会在方法完成时开始和结束
如果您使用的是JPA调用,那么所有提交都在该事务边界中
假设您正在保存entity1、entity2和entity3。现在,在保存entity3时,会出现一个异常,然后由于enitiy1和entity2在同一事务中,因此entity1和entity2将回滚到entity3
交易
@Component("mySubordinate")
public class CoreBusinessSubordinate {
public void doSomethingBig() {
System.out.println("I did something small");
}
public void doSomethingSmall(int x){
System.out.println("I also do something small but with an int");
}
}
@Component
@Aspect
public class CrossCuttingConcern {
@Before("execution(* com.intertech.CoreBusinessSubordinate.*(..))")
public void doCrossCutStuff(){
System.out.println("Doing the cross cutting concern now");
}
}
@Service
public class CoreBusinessKickOff {
@Autowired
CoreBusinessSubordinate subordinate;
// getter/setters
public void kickOff() {
System.out.println("I do something big");
subordinate.doSomethingBig();
subordinate.doSomethingSmall(4);
}
I do something big
Doing the cross cutting concern now
I did something small
Doing the cross cutting concern now
I also do something small but with an int
@Component("mySubordinate")
public class CoreBusinessSubordinate {
public void doSomethingBig() {
System.out.println("I did something small");
doSomethingSmall(4);
}
public void doSomethingSmall(int x){
System.out.println("I also do something small but with an int");
}
}
public void kickOff() {
System.out.println("I do something big");
subordinate.doSomethingBig();
//subordinate.doSomethingSmall(4);
}
I do something big
Doing the cross cutting concern now
I did something small
I also do something small but with an int
public void doSomethingBig() {
System.out.println("I did something small");
//doSomethingSmall(4);
((CoreBusinessSubordinate) AopContext.currentProxy()).doSomethingSmall(4);
}