Question

We have a Spring bean implemented as a singleton (default). This bean is used as part of an web-service, and at times when multiple simultaneous requests are triggered, the responseholder (singleton bean) throws a NullPointerException when trying to retrieve. This usually happens when the response is build, and then a new request is triggered before sending the original response back.

Can this be due to the Singletion implementation of the bean? If yes, is there wouldn't changing to prototype solve my problem. What about initiating it with the new operator always? Will there be any performance impacts on doing so? Or is there a better way.

Any help would be greatly appreciated.

Edit:

Code details

public class BuildToolRequestProcessor {

private BuildToolResponse buildToolResponse;
.....


//And it has been referenced in the code in different methods, setting the response details..

public String process(BuildToolRequestXml buildToolRequestXml) throws Exception {

buildToolResponse.setLocation(location);
...


public String handleDetails(BuildToolRequestXml buildToolRequestXml) throws Exception {


buildToolResponse.setSchedule(schedule);
...

// And in another method, when I try to retrieve the Location, it throws a Null Pointer Exception..

buildToolResponse.getLocation().getPinCode()


//Bean configuration

<bean id="buildToolResponse"
      class="com.raj.buildTool.processor.BuildToolResponse"/>

Additional Notes: I tried introducing a delay before bulding the response of the first request, shooting another request. The second request resets the Location to NULL, and hence NPE is thrown while trying to retrieve the Location. Could this be because of the singleton? Also I haven't used initialized the buildToolResponse again with the new operator, but the class BuildToolResponse extends from BuildToolResponseBuilder, which I am initializing using 'new' to build the response.

Was it helpful?

Solution

Can this be due to the Singletion implementation of the bean? If yes, is there wouldn't changing to prototype solve my problem.

If you have a singleton bean, make sure that this bean does not maintain any state. This means, it should not have any field that is reinitialized based on some methods, except for the injection of another beans or resources that is done by Spring. This may cause concurrency issues, specially when the bean is used in several threads (in this case, to attend multiple requests done to your web service).

This is an example of a bad design for a Spring bean that will be used on multiple threads:

@Component
public class SingletonByDefaultBean {
    private StringBuilder responseBuilder;

    @Autowired
    private FooService fooService;

    public String methodUsedInSeveralThreads() {
        //here you will have a concurrency issue
        responseBuilder = new StringBuilder();
        //write contents into the response
        //...
        //return the response
        return responseBuilder.toString();
    }
}

To solve this, you have two approaches:

  1. Remove any state of the bean and move the attributes into method local variables:

    @Component
    public class SingletonByDefaultBean {
        //private StringBuilder responseBuilder;
    
        @Autowired
        private FooService fooService;
    
        public String methodUsedInSeveralThreads() {
            StringBuilder responseBuilder = new StringBuilder();
            //write contents into the response
            //...
            //return the response
            return responseBuilder.toString();
        }
    }
    
  2. Change the scope of the bean to prototype

    @Component
    @Scope("prototype")
    public class SingletonByDefaultBean {
        private StringBuilder responseBuilder;
    
        @Autowired
        private FooService fooService;
    
        public String methodUsedInSeveralThreads() {
            responseBuilder = new StringBuilder();
            //write contents into the response
            //...
            //return the response
            return responseBuilder.toString();
        }
    }
    

What about initiating it with the new operator always?

Refer to this answer to know how you can create instances your classes manually and make them been managed by Spring. It is not that easy and I would recommend using these approaches only if you really understand what you're doing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top