2017-02-11 2 views
0

Я относительно новый для Spring ботинке и начал с очень простым примером из их getting started site, что (на стороне контроллера):Как обрабатывать несколько запросов параллельно с @RestController от SpringBoot?

@RestController 
public class HelloController { 

    @RequestMapping("/") 
    public String index() { 
     return "Greetings from Spring Boot!"; 
    } 

} 

Что я хочу сейчас, что многократный (потенциально длительные) запросы того же контроллера может обслуживаться в parallel.

Поскольку я уже узнал, что @RestController будет экземпляр, как одноэлементные, то ясно для меня, что множественные запросы (которые обрабатываются таким же способом) будут обработаны последовательно . Обновление: My bad: Я думал, что это связано с тем, что контроллер был синглом. Но верно: почему он не может работать параллельно?

Так что я изменил приведенный выше пример, как следует, так что новый экземпляр контроллера создается при каждом запросе и с некоторыми средствами проверки того, что происходит на самом деле:

@RestController 
@Scope(value = "request") 
public class HelloController { 

    private static AtomicInteger count = new AtomicInteger(0); 

    public HelloController() { 
     count.incrementAndGet(); 
    } 

    @PostConstruct 
    public void init() { 
     System.out.println("start request " + count); 
    } 

    @PreDestroy 
    public void onDestroy() { 
     System.out.println("end request " + count); 
    } 

    @RequestMapping("/") 
    public String index() throws InterruptedException { 
     LocalDateTime now = LocalDateTime.now(); 
     TimeUnit.SECONDS.sleep(15); 
     System.out.println(now); 
     return "Greetings from Spring Boot! " + now + " " + count.get(); 
    } 

} 

Теперь я хотел бы ожидать, чтобы увидеть, что запросы обрабатываются параллельно в течение примерно 15 секунд, но на самом деле я вижу только то, что он, очевидно, обрабатываются последовательно, и что она занимает 30 секунд (на стандартный вывод):

start request 1 
2017-02-11T14:19:47.429 
end request 1 
start request 2 
2017-02-11T14:20:02.467 
end request 2 

Так что мой вопрос: Как я могу добиться, чтобы такие запросы обрабатывались в параллельно, поскольку, очевидно, недостаточно создать экземпляр для каждого запроса?


Маленькая ремарка: я уже пробовал использовать @Asnync аннотацию в сочетании с @EnableAsync для класса приложений, но это, кажется, «огонь и забыть», что я не могу получить ответ, чтобы показать на стороне клиента ,

Несколько статей здесь, в stackoverflow (например, this и this) были интересными, но также не отвечали на мой вопрос, и этот учебник не касался asynchronous methods.


Update: Так как несколько человек указали, что проблема может быть связана с тем, как я проверил, я попытался запустить его с помощью другого браузера. Интересно, что я столкнулся с такими же проблемами как в Chrome, так и в Firefox. Но при выполнении одного запроса от каждого, он показал ожидаемое поведение (обслуживающий запросы параллельно) - так что я был одурачен ... фрезы

+0

Как вы выполняете параллельные запросы? – Andremoniy

+0

Как вы можете проверить свою конечную точку HelloController? Используя ваш браузер (открыть 2 вкладки) или модульное тестирование (используйте потоки)? – algojava

+1

«Поскольку я уже узнал, что @RestController будет создан как singleton, для меня ясно, что несколько запросов (которые обрабатываются одним и тем же методом) будут обрабатываться последовательно». Это утверждение неверно. В контейнере сервлета каждый запрос обрабатывается в другом потоке. Если ваш метод контроллера не синхронизирован, запросы будут обрабатываться вашим контроллером в parrallel – gregfqt

ответ

1

Вы писали:

Так как я уже узнал, что @RestController будет создан как singleton, для меня ясно, что несколько запросов (которые являются , обработанные одним и тем же методом) будут обрабатываться последовательно.

"... будут обрабатываться последовательно" - это ложное утверждение. Я даже понятия не имею, на каком основании это было сделано.Пока вы не синхронизируете метод (или будете использовать другую технологию блокировки), он будет доступен путем одновременного умножения потоков.

Во втором случае вы только что настроили его для создания нового экземпляра для каждого запроса. У меня есть только одна идея, объясняющая, почему вы получаете последовательные результаты в отладчике: вы также выполняете эти запросы из браузера.

Если вы хотите проверить, как многократные запросы обрабатываются даже в первом случае, просто откройте отдельные вкладки в браузере и начните запросы почти одновременно.

+0

Спасибо, что ответили! :) Я тестировал это в двух вкладках одного и того же браузера и запускал один запрос сразу после другого (определенно в течение 15 секунд), поэтому запросы выполнялись параллельно, я бы предположил, не так ли? Но я думаю, вы правы, указав, что одно из моих предположений было неправильным ... спасибо! – philonous

1

Контроллер, являющийся одноэлементным, не имеет никакого отношения к тому, доступен ли он одновременно.

Вам действительно не нужно использовать область определения, основанную на запросах, если у вас нет некоторого изменяемого поля, которое не может быть разделено между потоками, но реализация чего-то подобного, вероятно, является просто плохим дизайном.

Я предполагаю, что причина, по которой вы видите два запроса, занимает 30 секунд, состоит в том, что вы arent на самом деле делаете параллельные запросы, а вы ожидаете завершения первого запроса до начала второго.

+0

Прежде всего: Спасибо за ваш ответ! :) Ну, я делал два запроса в двух отдельных окнах браузера, второй - через две-три секунды после первого. И я ожидаю, что оба запроса будут обработаны в течение примерно 18 секунд - или мое предположение здесь неверно? – philonous

+0

Да, если ваш запрос спит в течение 15 секунд, и вам потребуется три секунды, чтобы пройти между каждой вкладкой браузера, тогда весь процесс займет 18 секунд. – Magnus

1

Я использую весну с 2009 года, я знаю, что их контроллер является Singleton. Но это не значит, что они обрабатывают ваш запрос последовательно (дождитесь завершения одного из них, затем выполните следующий).

Примеры кода с сайта Spring Boot могут обрабатывать параллельный запрос. Он создаст одиночный экземпляр HelloController, но Spring может одновременно звонить index() (параллельно).

@RestController 
public class HelloController { 

    @RequestMapping("/") 
    public String index() { 
     return "Greetings from Spring Boot!"; 
    } 

} 
Смежные вопросы