Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/399.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring-@Transactional-后台会发生什么?_Java_Spring_Spring Aop_Spring Jdbc_Transactional - Fatal编程技术网

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将在事务中封装该方法

但是,我有以下疑问:

  • 我听说Spring创建了一个代理类?有人能更深入地解释一下吗该代理类中实际驻留的是什么?实际的类发生了什么?我如何才能看到Spring创建的代理类
  • 我还在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()

  • 客户端从他的角度调用目标上的方法,并被代理静默地拦截
  • 如果定义了before方面,代理将执行它
  • 然后,执行实际的方法(目标)
  • 返回后和投掷后是可选的方面 在方法返回和/或方法抛出 例外情况
  • 之后,代理执行After方面(如果已定义)
  • 最后,代理返回到调用客户端

  • (我被允许发布这张照片,条件是我提到了它的起源。作者: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);
    }