[英]How to use blocking queue in Spring Boot?
I am trying to use BlockingQueue inside Spring Boot.我正在尝试在 Spring 引导中使用 BlockingQueue。 My design was like this: user submit request via a controller and controller in turn puts some objects onto a blocking queue.我的设计是这样的:用户通过 controller 提交请求,controller 依次将一些对象放入阻塞队列。 After that the consumer should be able to take the objects and process further.之后,消费者应该能够获取对象并进一步处理。
I have used Asnyc, ThreadPool and EventListener.我使用过 Asnyc、ThreadPool 和 EventListener。 However with my code below I found consumer class is not consuming objects.但是,通过下面的代码,我发现消费者 class 没有消耗对象。 Could you please help point out how to improve?你能帮忙指出如何改进吗?
Queue Configuration队列配置
@Bean
public BlockingQueue<MyObject> myQueue() {
return new PriorityBlockingQueue<>();
}
@Bean
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(3);
executor.setQueueCapacity(10);
executor.setThreadNamePrefix("Test-");
executor.initialize();
return executor;
}
Rest Controller Rest Controller
@Autowired
BlockingQueue<MyObject> myQueue;
@RequestMapping(path = "/api/produce")
public void produce() {
/* Do something */
MyObject myObject = new MyObject();
myQueue.put(myObject);
}
Consumer Class消费类 Class
@Autowired
private BlockingQueue<MyObject> myQueue;
@EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
consume();
}
@Async
public void consume() {
while (true) {
try {
MyObject myObject = myQueue.take();
}
catch (Exception e) {
}
}
}
Your idea is using Queue
to store messages, consumer listens to spring events
and consume.你的想法是使用Queue
来存储消息,消费者监听spring events
并消费。 I didn't see your code have actually publish the event, just store them in queue
.我没有看到您的代码实际上已经发布了事件,只是将它们存储在queue
中。 If you want to use Spring Events, producers could like this:如果你想使用 Spring 事件,生产者可以这样:
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
public void doStuffAndPublishAnEvent(final String message) {
System.out.println("Publishing custom event. ");
CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
applicationEventPublisher.publishEvent(customSpringEvent);
}
If you still want to use BlockingQueue
, your consumer should be a running thread, continuously waiting for tasks in the queue, like:如果你仍然想使用BlockingQueue
,你的消费者应该是一个正在运行的线程,不断地等待队列中的任务,比如:
public class NumbersConsumer implements Runnable {
private BlockingQueue<Integer> queue;
private final int poisonPill;
public NumbersConsumer(BlockingQueue<Integer> queue, int poisonPill) {
this.queue = queue;
this.poisonPill = poisonPill;
}
public void run() {
try {
while (true) {
Integer number = queue.take(); // always waiting
if (number.equals(poisonPill)) {
return;
}
System.out.println(Thread.currentThread().getName() + " result: " + number);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
could check this code example可以检查这个代码示例
In the end I came up with this solution.最后我想出了这个解决方案。
Rest Controller Rest Controller
@Autowired
BlockingQueue<MyObject> myQueue;
@RequestMapping(path = "/api/produce")
public void produce() {
/* Do something */
MyObject myObject = new MyObject();
myQueue.put(myObject);
Consumer.consume();
}
It is a little bit weird because you have to first put the object on queue yourself then consume that object by yourself.这有点奇怪,因为您必须先自己将 object 放入队列,然后自己使用 object。 Any suggestions on improvement is highly appreciated.任何关于改进的建议都非常感谢。
@Async
doesn't actually start a new thread if the target method is called from within the same object instance, this could be the problem in your case.如果从同一个@Async
实例中调用目标方法,@Async 实际上不会启动新线程,这可能是您的问题。 Also note that you need to put @EnableAsync
on a config class to enable the @Async
annotation.另请注意,您需要将@EnableAsync
放在配置 class 上以启用@Async
注释。
See Spring documentation: https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling-annotation-support请参阅 Spring 文档: https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling
The default advice mode for processing @Async annotations is proxy which allows for interception of calls through the proxy only.处理 @Async 注释的默认建议模式是代理,它只允许通过代理拦截调用。 Local calls within the same class cannot get intercepted that way.同一个 class 内的本地呼叫不能以这种方式被拦截。 For a more advanced mode of interception, consider switching to aspectj mode in combination with compile-time or load-time weaving.对于更高级的拦截模式,请考虑结合编译时或加载时编织切换到 aspectj 模式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.