threadRetrieveStockInfoEuronext

threadRetrieveStockInfoEuronext

我注释了一个Thread类,如下所示:

@Transactional(propagation = Propagation.REQUIRED)
@Component
@Scope("prototype")
public class ThreadRetrieveStockInfoEuronext implements Runnable {
   ...
}


线程连接到Controller类,并通过Global.poolMultiple.execute(threadRetrieveStockInfoEuronext)进行调用;

public class RetrievelController {

    @Autowired
    private ThreadRetrieveStockInfoEuronext threadRetrieveStockInfoEuronext;

    @RequestMapping(value = "/.retrieveStockInfo.htm", method = RequestMethod.POST)
    public ModelAndView submitRetrieveStockInfo(@ModelAttribute("retrieveStockInfoCommand") RetrieveStockInfoCommand command, BindingResult result, HttpServletRequest request) throws Exception {

        Global.poolMultiple.execute(threadRetrieveStockInfoEuronext);
        return new ModelAndView(".retrieveStockInfo", "retrieveStockInfoCommand", command);
    }


全局类:

@SuppressWarnings("unchecked")
@Component
public class Global {

    // create ExecutorService to manage threads
    public static ExecutorService poolMultiple = Executors.newFixedThreadPool(10);
    public static ExecutorService poolSingle = Executors.newFixedThreadPool(1);
...
}


运行应用程序时,发生以下异常:


  java.lang.IllegalArgumentException:无法设置
  com.chartinvest.admin.thread.ThreadRetrieveStockInfoEuronext字段
  
  com.chartinvest.controller.RetrievelController.threadRetrieveStockInfoEuronext
  到com.sun.proxy。$ Proxy52

最佳答案

这是因为您的Runnable实现是一个带有@Transactional注释的Spring组件,并且在Spring中,通过将类的实际实例包装在处理事务的基于JDK接口的代理中,从而实现了声明式事务。因此,自动装配的实际对象不是ThreadRetrieveStockInfoEuronext的实例,而是其接口Runnable的实例,该接口委托给ThreadRetrieveStockInfoEuronext的实例。

解决此问题的通常方法是自动连接接口,而不是自动装配具体类型。但是在这种情况下,此类首先不应该是Spring组件,也不应该是事务性的。顺便说一句,使其成为原型,给您一种幻觉,即每次调用commitRetrieveStockInfo()时都会创建一个新实例,但这是不正确的:创建了一个实例并将其自动连接到RetrievelController单例中,因此对所有对象使用相同的可运行对象对控制器的请求。

只需将ThreadRetrieveStockInfoEuronext设为一个简单的类,使用new实例化它,将一个Spring bean作为参数传递,并使其run()方法调用该Spring bean的事务方法:

@Transactional
@Component
public class ThreadRetrieveStockInfoEuronextImpl implements ThreadRetrieveStockInfoEuronext {
    @Override
    void doSomething() { ... }
}

public class RetrievelController {

    @Autowired
    private ThreadRetrieveStockInfoEuronext threadRetrieveStockInfoEuronext;

    @RequestMapping(value = "/.retrieveStockInfo.htm", method = RequestMethod.POST)
    public ModelAndView submitRetrieveStockInfo(@ModelAttribute("retrieveStockInfoCommand") RetrieveStockInfoCommand command, BindingResult result, HttpServletRequest request) throws Exception {

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                threadRetrieveStockInfoEuronext.doSomething();
            }
        };

        Global.poolMultiple.execute(runnable);
        return new ModelAndView(".retrieveStockInfo", "retrieveStockInfoCommand", command);
    }

10-06 06:13