Correct way of self-contained shared queue in Spring
I have a producer-consumer model implemented in my application. On the one hand, the producer pushes objects for processing received from different sources, on the other hand, I have a consumer that will dequeue these events and process them.
Both producer and consumer are spring beans and are automatically discovered and both require a reference to this shared queue. I know I can define my beans in both xml file and Java config and pass this Queue parameter as constructor argument or via setter, but there is a way to import it automatically. The only idea, in my opinion, is to create a wrapper for this queue and then insert that wrapper:
@Component
public class QueueWrapper {
private final BlockingQueue<MyObject> sharedQueue = new LinkedBlockingQueue<>();
public void put(MyObject toPut) {
sharedQueue.put(toPut);
}
public MyObject take() {
return sharedQueue.take();
}
}
@Component
public class Producer {
@Autowire
private QueueWrapper queue;
....
}
@Component
public class Consumer {
@Autowire
private QueueWrapper queue;
....
}
Should I create this shell? I know the annotation @Resource
, but I've only used it with lists, maps and sets and don't actually know how to set up a Java config file. XML sample list from spring documentation page:
<util:list id="emails">
<value>pechorin@hero.org</value>
<value>raskolnikov@slums.org</value>
<value>stavrogin@gov.org</value>
<value>porfiry@gov.org</value>
</util:list>
And then the Java class:
@Component
public class SomeClass {
@Resource(name="emails")
private List<String> emails;
}
Is there a way to create a queue as such a resource in java config? Or are there other ways to inject a shared queue into different beans?
source to share
What Don Botstein suggested, you just have to use it like that.
@Configuration
public class QueueConfig {
@Bean
public BlockingQueue<MyObject> blockingQueue() {
return new LinkedBlockingQueue<>();
}
}
Then, in the Producer and Consumer class, do something like this:
@Component
public class Producer {
@Autowired
private QueueConfig queueConfig;
public void produceMyObject(MyObject myObject) {
queueConfig.blockingQueue.put(myObject);
}
}
source to share
Basically, you must define an annotated class @Configuration
to register a bean of a given type. For example.
@Configuration
public class AppConfig {
@Bean
public BlockingQueue<MyObject> sharedQueue() {
return new LinkedBlockingQueue<>();
}
}
The default bean name is method name ( sharedQueue
), or you can override the name in annotation ( @Bean(name="someName")
). The default scope is singleton, which can be changed using @Scope(...)
in method.
@Configuration
Classes are picked up during component scanning in the same way as @Component
annotated classes.
However, I see nothing wrong with using the wrapper class as you showed. Indeed, using a wrapper class will allow you to more easily add adaptations to your implementation in the future.
source to share