java - Spring 启动: Multi-layered @Services in RESTful controllers for many inbound requests

标签 java rest spring-boot sorting singleton

不确定这是否是代码审查或有关 Spring Boot 如何运行的问题 @Service具有许多入站请求的组件。如果这是一个问题,我当然可以在 StackExchange > 代码审查中重新发布?我们在 Spring Boot 中基本上有以下模式:

  • Spring Boot 应用
  • 处理 List<DocumentMetadata> 的 RESTful Controller 对象
  • RESTful Controller 使用数据管理 @Service处理 ocumentMetadata 的获取和排序对象
  • 数据管理 @Service使用自定义排序 @Service对这些 documentMetadata 进行排序对象

叙述:本质上,RESTful 端点将返回 List<DocumentMetadata>对象(对象列表,如果愿意的话)作为 ResponseEntity 。自定义排序实现为 @Service方法为sort() 。我的理解是 Spring Boot 将创建一个自定义排序的“单例”实例@Service公用事业。我在 google 上搜索了一些关于 Spring Boot 的问题 @Service和生命周期,并发现以下内容。这篇文章描述了一些导致我提出问题/评论的用法,Should service layer classes be singletons? ,尤其是这条评论“此外,Spring 单例中的可变状态绝对没问题,您只需要知道可以在该共享状态上执行哪些操作 - skaffman”。我还阅读了这篇文章,Can Spring Boot application handle multiple requests simultaneously? ,这似乎表明我们没问题,因为我们正在创建、排序和返回的对象是在 @GetMapping 内创建的。并传递到服务组件层,即它不共享。

我的问题:

  • 这是否是设计 RESTful 堆栈的正确方法?特别是我们需要的实用程序类...应该将它们完成为 @Service或如POJO在数据管理中使用的类@Service层。
  • 在 10-100 个请求同时到达 RESTful 端点的多请求情况下,自定义排序实用程序 @Service 会发生什么情况?和 sort()方法?是否 sort()方法按顺序服务每个请求?或者在不同线程中并行?
  • 每个请求是否都使用相同的排序方法,即自定义排序实用程序 @Service是一个“单例” 那么 sort() 怎么样?使用的方法?
  • 如果 sort() 方法确实是单一的,那么如果两个用户同时使用该方法,那么 1 个用户可能会得到另一个用户的排序列表吗?或者 Spring Boot 是否只是按顺序或在自己的线程中处理入站请求并避免任何混合。

代码片段:为了简洁起见,我删除了大部分代码。

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

我已在代码中确认 @Service 中没有维护/管理“共享”可变对象。层。唯一被修改和/或创建的对象是在 @Service 的方法中完成的。层。

提前谢谢...

最佳答案

正如我所看到的,您的困惑基于 Spring 的 Singleton 范围以及当 @Service 类为 Singleton 时 Spring 如何处理多个请求.

Spring 创建并绑定(bind) bean 作为 Singleton 对象,除非您使用 @Scope 注释或与范围相关的注释定义特定范围,例如 @SessionScope。您可能已经了解这一点。

如果您对多个线程上的 Singleton 对象有模糊不清,这个 answer提供了很好的解释。那么,关于你的问题;

  • 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?

是和否。如果您的 @Service 类是 singleton (必须是)且不可变(无状态),那么这是正确的方法。这意味着,您的 @Service 类不应该有任何可修改的字段。否则,您的 @Service 将导致不可预测的结果。

如果在此上下文中使用了POJO,则每次新线程启动时,对象实例化都会初始化新对象,这给我们带来了第二个问题;

  • 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?

当端点上有 10-100 个或数千个请求时,如果您使用了 POJO,它还会创建数千个额外的对象,这会不必要地污染堆,因为我们可以使用一个 singleton 对象@Service 注解。由于单例对象是不可变的(不会通过其方法调用保留任何更改)并在多个线程之间共享,因此能够同时执行而不会对线程产生任何副作用结果。

如果 sort() 发生在内存中并随后返回排序结果,则它会独立执行并包含在线程的执行中。

  • 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并不意味着它的函数不能共享,除非它们被专门同步。就您而言,我相信此 sort() 方法不是同步。因此,在每个线程上单独执行 sort() 方法没有问题(没有差异,因为我们的 singleton 对象是无状态/不可变的)。

  • 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.

你知道,Spring boot 是基于 Java EE 的。因此,基本上它使用 javax.servlet.ServletContext 类实例来处理此请求和响应流以及 Java EE 中的所有其他类由于Spring的巧妙设计,这个过程我们是看不到的。但流程是一样的。简而言之,每个请求都有与其绑定(bind)的单独的线程,并且这些请求线程永远不会混淆。该线程涉及整个过程,直到将响应分派(dispatch)给客户端。

你有没有注意到,除了特殊场景,我们不会手动创建线程?这是因为,Java EE 生态系统代表我们管理这些线程。

所以,你的问题的答案是,不,sort() 不会执行一次,并且无论有多少用户发出请求,一个请求的结果都不会出现在其他请求的响应对象中同时地。这个answer还提供了关于这些请求-响应机制如何在底层工作的精彩解释。

关于java - Spring 启动: Multi-layered @Services in RESTful controllers for many inbound requests,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60290669/

相关文章:

java - CompletionStage 是否总是将异常包装在 CompletionException 中?

java - 从数组中打印素数

Azure 人脸识别给出 "Attribute 'qualityForRecognition'仅支持recognition_03和recognition_04。”错误

java - 使 Spring JUnit 测试在测试数据库上运行

JavaMelody 阻碍 Spring Boot 测试

java - 如何使用 Maven 组件插件打包 Spring Boot Web 应用程序

java - 播放响亮声音的自动音量控制

java - 如何在eclipse的侧边栏中查看对象的方法

Rest API,在参数中使用 '/'

api - 具有复合 ID 的 REST 资源的 URL