Spring Boot: многоуровневые @Services в контроллерах RESTful для многих входящих запросов - PullRequest
0 голосов
/ 19 февраля 2020

Не уверен, что это обзор кода или вопросы о том, как Spring Boot работает с @Service компонентами со многими входящими запросами. Если это вопрос, который я, конечно, могу опубликовать повторно в StackExchange> Code Reviews? В основном у нас есть следующий шаблон в Spring Boot:

  • Приложение Spring Boot
  • Контроллеры RESTful, которые обрабатывают List<DocumentMetadata> объекты
  • Контроллер RESTful использует Data Management @Service для обработки извлечения и сортировки ocumentMetadata объектов
  • Управление данными @Service использует пользовательскую сортировку @Service для сортировки этих documentMetadata объектов

Описание: По сути, конечная точка RESTful вернет List<DocumentMetadata> объектов (список объектов, если хотите) как ResponseEntity. Пользовательская сортировка реализована как @Service с методом для sort(). Насколько я понимаю, Spring Boot создаст "singleton" экземпляр утилиты Custom sorting @Service. Я погуглил несколько вопросов о Spring Boot @Service и жизненном цикле и обнаружил следующее. Эта публикация, в которой описывалось некоторое использование, которое привело к моим вопросам / обзору, Должны ли классы уровня обслуживания быть одиночными? , особенно этот комментарий "Кроме того, изменяемое состояние в синглтоне Spring абсолютно нормально, вам просто нужно знать, какие операции могут быть выполнены в этом общем состоянии - скаффман ". Я также прочитал в этой публикации, Может ли приложение Spring Boot обрабатывать несколько запросов одновременно? , что, по-видимому, говорит о том, что мы в порядке, поскольку объект, который мы создаем, сортируем и возвращаем, создается в @GetMapping и передается в слои компонентов службы, т. е. он не является общим.

Мои вопросы:

  • Является ли это даже правильным способом создания стека RESTful? В частности, классы Utility, которые нам нужны ... должны быть выполнены как @Service или как POJO классы, используемые в слое Data Management @Service.
  • В ситуации с несколькими запросами, когда 10- 100 запросов сразу попадают в конечную точку RESTful, что происходит с утилитой пользовательской сортировки @Service и методом sort()? Обслуживает ли метод sort() каждый запрос последовательно? или параллельно в разных потоках?
  • Каждый запрос использует один и тот же метод сортировки, т. е. утилита пользовательской сортировки @Service - это "singleton" , так как же используется метод 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.

Заранее спасибо ...

1 Ответ

1 голос
/ 19 февраля 2020

Как я вижу, ваша путаница связана с областью Singleton Spring и с тем, как Spring обрабатывает множественные запросы, когда Singleton классы *1003*.

Spring создают и связывают beans как Singleton объектов, если вы не определите конкретную область видимости, используя аннотацию @Scope или аннотацию, соответствующую области действия, например @SessionScope. Возможно, вы уже знаете об этом.

Если у вас есть размышления о Singleton объектах в нескольких потоках, этот ответ дает отличное объяснение. Итак, о ваших вопросах;

  • Является ли это даже правильным способом создания стека RESTful? В частности, классы Utility, которые нам нужны, должны ли они быть выполнены как @Service или как POJO классы, используемые в слое Data Management @Service?

Да и нет. Это правильный путь, если ваш @Service класс singleton (должен быть) и неизменный (без учета состояния). Это означает, что ваш класс @Service не должен иметь никаких изменяемых полей. В противном случае ваш @Service приведет к непредсказуемым результатам.

Если в этом контексте используется POJO, то создание экземпляра объекта будет инициализировать новый объект каждый раз, когда запускается новый поток, что приводит нас к вашему второй вопрос;

  • В ситуации с несколькими запросами, когда 10-100 запросов одновременно попадают в конечную точку RESTful, что происходит с утилитой пользовательской сортировки @Service и методом sort() ? Обслуживает ли метод sort() каждый запрос последовательно? или параллельно в разных потоках?

Когда 10-100 или тысячи или запросы попадают в конечную точку, если вы использовали POJO, он также создает тысячи дополнительных объектов, которые загрязняют кучу излишне, поскольку мы можем использовать один singleton объект, используя аннотацию @Service. Поскольку объект singleton равен immutable (который не будет сохранять никаких изменений при вызове методов) и совместно используется несколькими потоками, он может выполняться одновременно без каких-либо побочных эффектов на результат.

Если sort() происходит в памяти и впоследствии возвращает отсортированные результаты, он выполняется независимо, завернутый в выполнение потока.

  • Каждый запрос использует один и тот же метод сортировки, т. Е. Утилита пользовательской сортировки @Service является "singleton" , так как же используется метод sort()?

Singleton не означает, что его функции не могут быть разделены, если они специально не являются synchronized. В вашем случае, я считаю, что этот sort() метод не synchronized. Таким образом, нет проблем с выполнением метода sort() для каждого потока отдельно (нет расхождений, поскольку наш объект singleton не имеет состояния / неизменен).

  • Если метод sort() действительно одиночен, может ли 1 пользователь в конечном итоге отсортировать List другого пользователя, если оба пользователя одновременно нажмут на метод? Или Spring Boot просто обрабатывает входящие запросы последовательно или в своих собственных потоках и избегает какого-либо смешивания.

Вы знаете, что загрузка Spring основана на Java EE. Таким образом, в основном он использует экземпляры класса javax.servlet.ServletContext для обработки этого потока request и response, и целый ряд других классов из Java EE вовлечены в этот процесс, который мы не можем увидеть из-за умного замысла Spring. Но поток тот же. Короче говоря, каждый request имеет отдельные thread, связанные с ним, и эти request-threads никогда не перепутываются. Это thread включает весь процесс, пока ответ не будет отправлен клиенту.

Вы когда-нибудь замечали, что мы не создаем поток вручную, за исключением специального сценария ios? Это потому, что Java EE-экосистемы управляют этими потоками от нашего имени.

Итак, ответ на ваш вопрос: нет, sort() не будет выполнен один раз, и никогда результаты одного запроса не окажутся в ответе другого запроса. объект, независимо от того, сколько тысяч пользователей делают запрос одновременно. Этот ответ также дает блестящее объяснение того, как работает механизм запроса-ответа.

...