为什么@Scheduled注释不适用于@Transaction批注。春季启动

时间:2017-07-27 15:52:22

标签: java spring spring-boot scheduled-tasks spring-transactions

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

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. 实施ConcurrentTaskScheduler 并替换ScheduledMethodRunnable的对象(即我的班级) 对象ScheduledMethodRunnable与代理。

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

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

    谢谢!

2 个答案:

答案 0 :(得分:1)

之所以发生这种情况,是因为要处理两个注释MAGIC。

我想有几件事情发生了:

  1. UserServiceImpl已创建。
  2. 处理
  3. @Scheduled注释并存储对bean的引用以在适当的时候调用它。
  4. @Transactional注释已处理完毕。它创建代理,存储对原始bean的引用。原始bean在应用程序上下文中被替换为代理。
  5. 如果第2步和第3步以不同的顺序通过,那么你没有问题。

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

    基本上有两个解决方案

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

      @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();
          }
      }
      

      我个人推荐第二种方法。

答案 1 :(得分:0)

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

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

这有两个含义:

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

您也可以使用AspectJ模式代替Spring Proxies,它将克服此问题。而且AspectJ事务性方面甚至被编织成私有方法(已在Spring 3.0中进行了检查)。

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