【问题标题】:@Transactional with static method@Transactional 使用静态方法
【发布时间】:2014-06-27 11:54:01
【问题描述】:

为什么我们不能使用 @Transactional 的静态方法来管理我的 spring 项目中的事务?

@Transactional 适用于非静态方法但不适用于静态方法有什么具体原因吗?

【问题讨论】:

  • 因为不支持。
  • 我知道它不受支持,但有任何具体原因使其不受支持...
  • 我对此进行了搜索,看起来 cglib 无法创建 static 方法。 cglib 是 Spring 用来动态创建代理的库。

标签: spring transactions


【解决方案1】:

为了理解为什么像您所提议的那样不起作用,您必须首先从高层次上了解 Spring 如何处理使用 @Transactional 的 bean。

当您将方法或类注释为@Transactional 并使其成为 Spring Bean 时,Spring 有效地为该类创建代理(使用 JDK 动态代理或 CGLIB 代理)。这意味着,无论何时使用您的类(来自 Spring 托管代码),立即调用的不是您的代码,而是首先执行所需操作的代理,然后调用您的代码(在缓存支持您的代码甚至可能根本不会被调用)。 这里要记住的关键是调用代码(如果您愿意,调用站点)根本不会改变,并且对所需目标方法(代理方法)的调用由 JVM 使用相同的字节码(invokevirtual 或 invokeinterface)。

考虑到这一点,不支持静态的原因就很清楚了。 您不能为静态方法创建代理!当然,Java 动态代理不能做到这一点,CGLIB 也不能。

支持这样的功能需要更改调用代码的字节码,因为调用静态方法是通过字节码中的invokestatic实现的,它对目标方法进行硬编码。

This部分Spring文档详细解释了Spring AOP

【讨论】:

  • okie..我知道你解释了什么......使用一些静态代理模式为静态方法创建代理很难吗?或者我们不能为静态方法创建代理,如果不是为什么?
  • 调用静态方法时,没有类的对象在起作用,因此没有任何东西可以代替它,这意味着不能使用代理。我能想到的唯一可行的方法是更改​​字节码,但我不知道这是否可行
【解决方案2】:

如果您使用的是 AspectJ,这里有一个简单但难看的解决方法:

public static void doWhatever(final String param) {
    new Runnable() {
        @Transactional
        public void run() {
            // do whatever in transaction...
        }
    }.run();
}

【讨论】:

    【解决方案3】:

    这是可行的:

    1. @EnableTransactionManagement(mode = ASPECTJ)(或其 XML 等效项)
    2. 使 AspectJ 工作所需的所有配置
    3. 注册一个自定义方面来处理 @Transactional 而不是像 this one 这样的静态方法我只是偶然发现(没有测试它)

    注意:在this post 中,我询问了如何制作包私有方法@Transactional

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-17
      • 1970-01-01
      • 2011-10-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多