Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way of autowiring shared queue in Spring

I've got kind of producer-consumer pattern implemented in my application. On one end producer pushes entities to process recieved from different sources, on the other hand I've got consumer which take this events out of the queue and process them.

Both producer and consumer are spring beans and discovered automatically and both require link to this shared Queue. I know that I can define my beans in either xml file or Java configuration and pass this Queue as parameter as constructor argument or via setter, but is there a way to import it automatically. The only idea come to my mind is to create a wrapper for this queue and then inject this wrapper instead :

@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;
    ....
}

Does it worth creating this wrapper? I'm aware of @Resource annotation but I've used it with lists, maps and sets only and actually don't know how to configure resource Java config file. XML example of list from Spring documentation page:

<util:list id="emails">
    <value>[email protected]</value>
    <value>[email protected]</value>
    <value>[email protected]</value>
    <value>[email protected]</value>
</util:list>

And then Java class:

@Component
public class SomeClass {
   @Resource(name="emails")
   private List<String> emails;
}

Is there a way to create queue as such resource in java configuration? Or are there another ways to inject a shared queue to different beans?

like image 218
Oleksii Duzhyi Avatar asked Aug 03 '15 14:08

Oleksii Duzhyi


People also ask

Which is the correct Autowiring in Spring?

Autowiring ModesIt is the default autowiring mode. It means no autowiring bydefault. The byName mode injects the object dependency according to name of the bean. In such case, property name and bean name must be same.

What are possible ways of Autowiring in Spring boot?

XML. The autodetect mode uses two other modes for autowiring – constructor and byType. It first tries to autowire via the constructor mode and if it fails, it uses the byType mode for autowiring. It works in Spring 2.0 and 2.5 but is deprecated from Spring 3.0 onwards.


2 Answers

What Don Bottstein suggested will work, you just have to use it like this.

@Configuration
public class QueueConfig {

    @Bean
    public BlockingQueue<MyObject> blockingQueue() {
        return new LinkedBlockingQueue<>();
    }
}

Then in the class Producer and Consumer do something like this:

@Component
public class Producer {

    @Autowired
    private QueueConfig queueConfig;

    public void produceMyObject(MyObject myObject) {
        queueConfig.blockingQueue.put(myObject);
    }
}
like image 170
MattJ Avatar answered Oct 11 '22 15:10

MattJ


Basically, you would define a @Configuration annotated class to register a bean of the given type. E.g.,

@Configuration
public class AppConfig {
    @Bean
    public BlockingQueue<MyObject> sharedQueue() {
        return new LinkedBlockingQueue<>();
    }
}

The bean name defaults to the name of the method (sharedQueue in this case), or you can override the name in the annotation (@Bean(name="someName")). The default scope is singleton, which can be changed using @Scope(...) on the method.

@Configuration classes are picked up during component scanning just like @Component annotated classes.

However, I don't see anything wrong with using a wrapper class as you've illustrated. Indeed, using a wrapper class would allow you to more easily add in adaptations to the implementation down the road.

like image 29
Don Bottstein Avatar answered Oct 11 '22 15:10

Don Bottstein