我已经注释了一个Thread类,如下所示:
@Transactional(propagation = Propagation.REQUIRED)
@Component
@Scope("prototype")
public class ThreadRetrieveStockInfoEuronext implements Runnable {
...
}
Thread连接到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
答案 0 :(得分:3)
那是因为你的Runnable实现是一个Spring组件,用@Transactional
注释,并且在Spring中通过将类的实际实例包装在处理事务的基于JDK接口的代理中来实现声明式事务。因此,自动装配的实际对象不是ThreadRetrieveStockInfoEuronext的实例,而是其接口的实例Runnable,该实例委托给ThreadRetrieveStockInfoEuronext的实例。
此问题的常见解决方法是自动装配界面,而不是自动装配具体类型。但在这种情况下,这个类首先不应该是Spring组件,它也不应该是事务性的。 BTW,使它成为一个原型让你觉得每次调用submitRetrieveStockInfo()时都会创建一个新的实例,但这是错误的:创建一个单独的实例并自动装入RetrievelController单例,因此相同的runnable用于所有对控制器的请求。
只需将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);
}