0

Not sure if this is a code review or questions on how Spring Boot operates regarding @Service components with many inbound requests. If it is a question I can certainly re-post in StackExchange > Code Reviews? We basically have the following pattern in Spring Boot :

  • Spring Boot application
  • RESTful controllers that process List<DocumentMetadata> objects
  • RESTful controller uses a Data Management @Service to handle fetching and sorting of ocumentMetadata objects
  • Data Management @Service uses a Custom sorting @Service to do the sorting of these documentMetadata objects

Narrative : Essentially a RESTful endpoint will return a List<DocumentMetadata> objects (List of objects if you will) as a ResponseEntity. The custom sorting is implemented as an @Service with a method for the sort(). My understanding is that Spring Boot will create a "singleton" instance of the Custom sorting @Service utility. I've googled a number of questions on Spring Boot @Service and lifecycle, and found the following. This posting, which described some usage that led to my questions/review, Should service layer classes be singletons? , especially this comment "Also, mutable state within a Spring singleton is absolutely fine, you just need to be aware of what operations can be done on that shared state – skaffman". I also read thru this posting, Can Spring Boot application handle multiple requests simultaneously?, which seems to suggest we are ok since the object we are creating, sorting and returning is created within the @GetMapping and passed into the Service component layers, i.e. it's not shared.

My Questions :

  • Is this even the right way to design a RESTful stack? Specifically the Utility classes we need...should they be done as @Service or as POJO classes that get used within the Data Management @Service layer.
  • In a multi-request situation where 10-100 requests are hitting the RESTful endpoint at once, what happens to the Custom Sorting utility @Service and the sort() method? Does the sort() method service each request sequentially? or in parallel in different threads?
  • Is every request using the same sort method, i.e. the Custom Sorting utility @Service is a "singleton" so how is the sort() method utilized?
  • If the sort() method is truly single, could 1 user potentially end up with another user's sorted List if both Users hit the method simultaneously? Or does Spring Boot simply process the inbound requests in sequence or in their own threads and avoid any mixing.

Code snippets : I removed much of the code for brevity.

@RestController
@RequestMapping(value = "/search")
@CrossOrigin(origins = "*")
@Slf4j
public class SearchController {

    // @Service for Data handling...
    @Autowired
    private DataManagementService dataManagementService;

    @GetMapping(value="/viewable-documents")
    public SearchResponse getExternallyViewableDocuments(@RequestParam(required = false) Map<String, String> queryParams) {
        logger.debug("getViewableDocuments is called with {}", queryParams);

        SearchResponse searchResponse = new SearchResponse();

        // ENDPOINT : Calls the Data Management handling @Service...
        SearchResponse response = dataManagementService.getDocuments(queryParams);

    }
}

@Service
public class DataManagementServiceImpl implements DataManagementService {

    // CUSTOM SORT UTILITY : Autowired with setter...
    private DocumentSortUtility documentSortUtility;

    @Autowired
    public void setDocumentSortUtility(DocumentSortUtility setValue) {
        this.documentSortUtility = setValue;
    }


    @Override
    public SearchResponse getDocuments(Map<String, String> request) {

        if (request.get("sort") != null && request.get("sort").equals("true")) {

            // SORT : Call the custom sort...
            return serviceImpl.populateResponse(this.documentSortUtility.sort(response));

        } else {
            return serviceImpl.populateResponse(response);
        }
    }
}

@Service
public class DocumentSortUtility {

    public List<DocumentMetadata> sort(List<DocumentMetadata> documentMetadataList) {
        log.debug("Un Sorted:"+documentMetadataList);

        // Do custom sort of documentMetadataList and place in retList...

        log.debug("Sorted:"+retList);   
        return retList;
    }
}

I have confirmed in the code that there are no "shared" mutable objects being maintained/managed in the @Service layers. The only objects being modified and/or created are done within the methods of the @Service layers.

Thx in advance...

Sachith Dickwella
  • 1,388
  • 2
  • 14
  • 22
lincolnadym
  • 909
  • 1
  • 12
  • 29

1 Answers1

2

As I can see, your confusion based on the Spring's Singleton scope and how Spring handles multiple requests when @Service classes are being Singleton.

Spring create and bind beans as Singleton objects unless you define particular scope using @Scope annotation or annotation respective to the scope, like @SessionScope. You may already know about this.

If you have fuzz about Singleton objects on multiple threads, this answer provides excellent explanation. So, about your questions;

  • Is this even the right way to design a RESTful stack? Specifically the Utility classes we need, should they be done as @Service or as POJO classes that get used within the Data Management @Service layer?

Yes and no. This is the right way if your @Service class is singleton (it must be) and immutable (Stateless). Which means, your @Service class should not have any modifiable field. Otherwise, your @Service would lead to unpredictable results.

If a POJO's been used in this context, object instantiation would initialize new object each time when a new thread started, which brings us to your second question;

  • In a multi-request situation where 10-100 requests are hitting the RESTful endpoint at once, what happens to the Custom Sorting utility @Service and the sort() method? Does the sort() method service each request sequentially? or in parallel in different threads?

When 10-100 or thousands or requests hit on the endpoint, if you have used a POJO, it also create thousands of additional objects which pollute the heap unnecessarily since we can use one singleton object using @Service annotation. Since the, singleton object is immutable (which wouldn't keep any change by its method invocations) and shared between multiple thread, capable to execute simultaneously without any side effect on the result.

If the sort() happens in memory and return the sorted results afterward, it executes independently wrapped in thread's execution.

  • Is every request using the same sort method, i.e. the Custom Sorting utility @Service is a "singleton" so how is the sort() method utilized?

Singleton doesn't mean that its functions cannot be shared unless they are specifically synchronized. In your case, I believe this sort() method is not synchronized. So, there's no problem to execute sort() method on each of the thread separately (no discrepancies as our singleton object is stateless/immutable).

  • If the sort() method is truly single, could 1 user potentially end up with another user's sorted List if both Users hit the method simultaneously? Or does Spring Boot simply process the inbound requests in sequence or in their own threads and avoid any mixing.

You know, that Spring boot is based on Java EE. So, basically it uses a javax.servlet.ServletContext class instances to handle this request and response flow and whole lot of other classes from Java EE involves in this process which we can't see due Spring's clever design. But the flow is the same. In a nutshell, each request has separate thread bound to it and those request-threads never gets mixed up whatsoever. That thread involves the whole process until response is dispatched to the client.

Have you ever notice, we don't create thread manually except for special scenarios? That because, Java EE ecosystems manage these threads behalf of us.

So, answer to your question is, no, sort() would not execute once and never ever one request's results end up in other request's response object, no matter how many thousand users make the request simultaneously. This answer also provide brilliant explanation about how these request - response mechanism work underneath.

Sachith Dickwella
  • 1,388
  • 2
  • 14
  • 22
  • Can you [please vote to undelete and reopen this question](https://stackoverflow.com/q/64365593/548225) – anubhava Feb 12 '21 at 18:46