user1386966
user1386966

Reputation: 3392

Difference between creating new instance and using scope prototype annotation in Spring

My application is listening to an exchange (using rabbitMQ), expecting to receive some API data and then should redirect it to the relevant place.

I'm using rxJava to subscribe on these changes, when the purpose is to open a new thread and send the request by creating RestClient each time -> it will receive the data, parse it, send it and then send the response back to queue.

My problem is that I want each time to create a new instance of my RestClient. Thought of using Springs Scope annotation : @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) but can't seem to understand how to use it and what will be the difference if I use new RestClient each time.

Can you please explain the advantage of using getBean over using new?

Here is the code:

class MyManager {

   @Autowired
   private WebApplicationContext context;
    ....
    ...
    ...

    @PostConstruct
    myListener.subscribeOn(Schedulers.computation()).subscribe(this::handleApiRequest);


    private void  handleApiRequest(ApiData apiData){

    // Option 1:
    RestClient client = new RestClient();
    client.handleApiRequest(apiData);

    //Option 2:
    // use somehow the prototype?
    RestClient x = (RestClient)context.getBean("restTest")..
    }
}



 @Service
 //@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) //NEEDED??
class RestClient {
 private String server;
  private RestTemplate rest;
  private HttpHeaders headers;
  ResponseEntity<String> responseEntity;

  @PostConstruct
  private void updateHeaders() {
    headers.add(Utils.CONTENT_TYPE, Utils.APPLICATION_JSON);
    headers.add(Utils.ACCEPT, Utils.PREFIX_ALL);
  }


  public void handleApiRequest(ApiData apiRequest) {
    sendRequest(apiRequest); //implemented
    sendResponse(); //implemented
  }


}


  @Bean(name = "restTest")
  @Scope("prototype")
  public RestClient getRestTemplate() {
    return new RestClient();
  }

Upvotes: 3

Views: 2032

Answers (3)

so-random-dude
so-random-dude

Reputation: 16485

First of all, resttemplate is thread-safe. Don't instantiate it per request or using new keyword (Constructor), that is a bad design. Because you commented out @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) here; and by default, spring will create a singleton bean of RestClient and you will get the same instance of RestClient wherever you autowire; so you are doing it right.

@Service
 //@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) //NEEDED??
class RestClient {

I have a question here though, in RestClient, where are you instantiating private RestTemplate rest; I am not seeing that in the code that you posted

And if you are moving to singleton scope from prototype scope as suggested, you can use @Autowired RestClient restClient;

instead of

@Autowired private WebApplicationContext context;
RestClient x = (RestClient)context.getBean("restTest")

Less boilerplate.

Upvotes: 3

asg
asg

Reputation: 2456

When you use any bean returned by context.getBean(), then lifecycle of that bean will be handled by Spring.

But if you initialise bean with new instance, you are responsible for object creation and it's life cycle. (And hence @PostConstruct and other spring annotations inside that class will be meaningless.) And any dependencies inside that bean will not be injected.

Upvotes: 1

Oleg
Oleg

Reputation: 6314

When you use context.getBean the returned instance is a Spring bean, spring handles dependency injection, configuration, lifecycle callbacks... . When you just create it using new none of that happens. In the example you gave the @PostConstruct method is going to be called only if you use context.getBean.

Upvotes: 1

Related Questions