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?

+3


source to share


2 answers


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);
    }
}

      

+4


source


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.

+1


source







All Articles