smi*_*tan 6 java spring-mvc background-process
我来自Perl背景,正在使用Spring编写我的第一个Java MVC Web应用程序.
我的webapp允许用户通过调用第三方SOAP服务来提交应用程序同步处理的订单.该项目的下一阶段是允许用户提交批量订单(例如包含500行的CSV)并异步处理它们.这是我现有控制器的片段:
@Controller
@Service
@RequestMapping(value = "/orders")
public class OrderController {
@Autowired
OrderService orderService;
@RequestMapping(value="/new", method = RequestMethod.POST)
public String processNewOrder(@ModelAttribute("order") Order order, Map<String, Object> map) {
OrderStatus orderStatus = orderService.processNewOrder(order);
map.put("orderStatus", orderStatus);
return "new";
}
}
Run Code Online (Sandbox Code Playgroud)
我计划创建一个新的@RequestMapping来处理传入的CSV并修改它OrderService以便能够将CSV分开并将各个订单持久保存到数据库中.
我的问题是:在MVC Spring应用程序中创建后台工作程序的最佳方法是什么?理想情况下,我将有5个线程处理这些订单,并且很可能来自队列.我已经读过@Async或提交过Runnable一个SimpleAsyncTaskExecutorbean,我不知道该走哪条路.一些例子对我有帮助.
我认为 Spring Batch 太过分了,并不是您真正想要的。它更多的是用于批处理,例如将所有订单写入文件,然后立即处理所有订单,而这似乎更像是异步处理,您只想拥有一个工作“队列”并以这种方式处理它。
如果确实如此,我会考虑使用 JMS 的发布/订阅模型。有多个 JMS 提供程序,例如 Apache ActiveMQ 或 Pivotal RabitMQ。本质上,您OrderService会将 CSV 分解为工作单元,将它们推送到 JMS 队列中,并且您将设置多个消费者来从队列中读取数据并执行工作任务。有很多方法可以配置它,但我只是创建一个类来保存工作线程并使线程数量可配置。这里的其他额外好处是:
但也有一些缺点。您现在有一个额外的故障点。您可能需要监视队列深度,并且在缓存消息时需要提供足够的空间来存储消息。此外,如果处理时间可能是一个问题,您可能需要监控队列中的处理速度,以确保它不会备份太多或破坏任何可能存在的 SLA。
编辑:添加示例... 如果我有一个线程类,例如:
public class MyWorkerThread implements Runnable {
private boolean run = true;
public void run() {
while (run) {
// Do work here...
}
// Do any thread cooldown procedures here, like stop listening to the Queue.
}
public void setRunning(boolean runState) {
run = runState;
}
}
Run Code Online (Sandbox Code Playgroud)
然后我将使用这样的类启动线程:
@Service("MyThreadManagerService")
public class MyThreadManagerServiceImpl implements MyThreadManagerService {
private Thread[] workers;
private int workerPoolSize = 5;
/**
* This gets ran after any constructors and setters, but before anything else
*/
@PostConstruct
private void init() {
workers = new Thread[workerPoolSize];
for (int i=0; i < workerPoolSize; i++) {
workers[i] = new Thread(new MyWorkerThread()); // however you build your worker threads
workers[i].start();
}
}
/**
* This gets ran just before the class is destroyed. You could use this to
* shut down the threads
*/
@PreDestroy
public void dismantle() {
// Tell each worker to stop
for (Thread worker : workers) {
worker.setRunning(false);
}
// Now join with each thread to make sure we give them time to stop gracefully
for (Thread worker : workers) {
worker.join(); // May want to use the one that allows a millis for a timeout
}
}
/**
* Sets the size of the worker pool.
*/
public void setWorkerPoolSize(int newSize) {
workerPoolSize = newSize;
}
}
Run Code Online (Sandbox Code Playgroud)
现在您有了一个很好的服务类,您可以添加方法来监视、重新启动、停止等所有工作线程。我将其设为 是@Service因为它感觉比简单的更正确@Component,但从技术上讲,它可以是任何东西,只要 Spring 知道在自动装配时选择它即可。服务类上的方法init()用于启动线程,并dismantle()用于优雅地停止它们并等待它们完成。它们使用@PostConstruct和@PreDestroy注释,因此您可以随意命名它们。您可能会有一个构造函数MyWorkerThread来设置队列等。另外,作为免责声明,这都是从内存中编写的,因此可能存在一些轻微的编译问题或方法名称可能略有偏差。
可能已经有课程可以做这类事情,但我自己从未见过。有人知道使用现成零件的更好方法吗,我很乐意接受更好的教育。