java - Spring JPA 线程 : IllegalArgumentException Exception

标签 java spring hibernate jpa transactional

我已经注释了一个 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: Can not set com.chartinvest.admin.thread.ThreadRetrieveStockInfoEuronext field

com.chartinvest.controller.RetrievelController.threadRetrieveStockInfoEuronext to com.sun.proxy.$Proxy52

最佳答案

那是因为您的 Runnable 实现是一个 Spring 组件,用 @Transactional 注释,并且在 Spring 中,通过将类的实际实例包装在基于 JDK 接口(interface)的代理中来实现声明式事务处理交易。因此, Autowiring 的实际对象不是 ThreadRetrieveStockInfoEuronext 的实例,而是其接口(interface) Runnable 的实例,该接口(interface)委托(delegate)给 ThreadRetrieveStockInfoEuronext 的实例。

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

只要使 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);
    }

关于java - Spring JPA 线程 : IllegalArgumentException Exception,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32799093/

相关文章:

java - JPAContainer 保持数据库的连接打开

hibernate - 如何在grails中缓存(整个表或Domain.list()方法的结果)?

java - 在 java 应用程序、gwt 或 android 应用程序中存储常量值

java - 如何在 Spring/OpenJPA 1 中重新创建更新行锁定的选择

java - 为什么不直接使用构造函数呢?

spring - Keycloak:作为 docker 服务运行时无效的 token 颁发者

java - Spring Boot项目空指针异常

java - 如何在不复制代码的情况下在 Java Web 应用程序中包含 jsp 页面?

java - 将路径传递给 exec

java - 将额外元素添加到逗号分隔列表中