为什么@Scheduled批注不适用于@Transaction批注。弹簧靴

我有一个问题:为什么当我们用和注释方法时,事务不起作用?我知道调用我的类而不是Spring创建的代理类,但无法理解这种行为。@Scheduled@Transaction@Scheduled

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserServiceImpl implements UserService {

    @Override
    @Scheduled(fixedRateString = "${somestring}",initialDelayString = "${anotherstring}")
    @Transactional
    public void doSomething() {

        }
    }

我有两个解决这个问题的解决方案:

  1. 从方法调用代理。Scheduled

  2. 实现对象 (即使用我的类) 并将其替换为带有代理的对象 。ConcurrentTaskSchedulerScheduledMethodRunnableScheduledMethodRunnable

但是这种解决方案非常不方便。

你能解释一下为什么这样工作吗?@Scheduled

谢谢!


答案 1

发生这种情况是因为要处理这两个注释,都会使用MAGIC。

我想有几件事会发生:

  1. UserServiceImpl已创建。
  2. @Scheduled处理注释并存储对 Bean 的引用以在适当的时间调用它。
  3. @Transactional处理批注。它创建存储对原始Bean的引用的代理。原始 Bean 被替换为应用程序上下文中的代理。

如果步骤2和3以不同的顺序通过,那么您没有问题。

我不知道如何控制注释的处理顺序。我甚至不确定这是否可能。

基本上有两种解决方案

  1. 使用不同类型的魔法来处理。默认方法是创建代理对象,但可以指示检测当前类。@TransactionSpring
  2. 将其拆分为两个类,每个类将具有只有一个注释的方法。

例:

@Service
public class UserServiceImpl implements UserService {

    @Override
    @Transactional
    public void doSomething() {

    }
}

@Service
public class UserServiceScheduler {

    @Inject
    private UserService service;

    @Scheduled(fixedRateString = "${somestring}",initialDelayString = "${anotherstring}")
    public void doSomething() {
         service.doSomething();
    }
}

我个人推荐第二种方法。


答案 2

问题不是私有的或公开的,问题是:如何调用它以及使用哪种AOP实现!

如果您使用(默认)Spring代理AOP,则只有当调用通过代理时,才会考虑Spring提供的所有AOP功能(如)。-- 如果从一个 Bean 调用带注释的方法,则通常会出现这种情况。@Transational

这有两个含义:

  • 因为私有方法不能从另一个 Bean 调用(唯一的例外是反射),所以不考虑它们的注释。@Transactional
  • 如果该方法是公共的,但它是从同一个bean调用的,那么它也不会被考虑在内(仅当使用(默认)Spring Proxy AOP时才是正确的)。

您还可以使用aspectJ模式,而不是Spring代理,这将克服这个问题。AspectJ Transactional Aspects甚至被编织到私有方法中(在Spring 3.0中进行了检查)。

参考: http://docs.spring.io/spring/docs/3.2.4.RELEASE/spring-framework-reference/html/aop.html#aop-proxying


推荐