Подтвердить что ты не робот

Должны Spring классы MVC быть потокобезопасными

Если вы используете Spring MVC, должны ли ваши классы компонентов (@Controller, @Service, @Repository) быть потокобезопасными?

То есть, если у меня есть метод @RequestMapping в моем @Controller, может ли этот метод вызываться одновременно для одного и того же объекта контроллера более чем одним потоком?

(У этого вопроса был задан вопрос до, но он не ответил как таковой).

4b9b3361

Ответ 1

Учитывая

@Controller
public class MyController {
    @RequestMapping(value = "/index")
    public String respond() {
        return "index";
    }
}

Spring создаст экземпляр MyController. Это связано с тем, что Spring анализирует вашу конфигурацию, <mvc:annotation-driven>, видит @Controller (что похоже на @Component) и создает экземпляр аннотированного класса. Поскольку он видит @RequestMapping, он генерирует для него HandlerMapping, см. здесь.

Любые HTTP-запросы, полученные DispatcherServlet, будут отправляться в этот экземпляр контроллера через зарегистрированный ранее HandlerMapping, вызывая respond() через java-отражение на этом экземпляре.

Если у вас есть поля экземпляров, например

@Controller
public class MyController {
    private int count = 0;
    @RequestMapping(value = "/index")
    public String respond() {
        count++;
        return "index";
    }
}

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

Вам нужно понять, как работают контейнеры Servlet. Контейнер создает экземпляр вашего экземпляра Spring MVC DispatcherServlet. Контейнер также управляет пулом потоков, который он использует для ответа на соединения, т.е. HTTP-запросы. Когда такой запрос поступает, контейнер выбирает поток из пула и в рамках этого потока выполняет метод service() на DispatcherServlet, который отправляет правильный экземпляр @Controller, который Spring зарегистрирован для вас (из вашего конфигурации).

Итак, YES, Spring Классы MVC должны быть потокобезопасными. Вы можете сделать это, играя с различными областями для полей экземпляра класса или вместо этого вместо этого вместо них должны быть локальные переменные. В противном случае вам потребуется добавить соответствующую синхронизацию вокруг критических разделов в вашем коде.

Ответ 2

По умолчанию контроллеры являются одноточечными и, следовательно, должны быть потокобезопасными. Однако вы можете настроить контроллеры для запроса или сеанса, например:

@Controller
@Scope("session")
public class MyController {

    ...
}

Контроллеры с областью сеанса могут быть полезны для управления состоянием сеанса. Хорошее описание различных шаблонов можно найти в Использование сеансов в Spring -MVC (включая "scoped-proxies" ) и в Как получить объект сеанса в Spring MVC. Некоторые из представленных шаблонов требуют области запроса.

Область запроса также полезна, если у вас есть данные, которые вы не можете позволить вычислить более чем на один запрос.

Ответ 3

Да, конечно.

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

Ответ 4

В основном ответ должен быть да и нет. За исключением очень серьезной причины. Не потому, что Spring синхронизирует работу для you-, он этого не делает (по умолчанию контроллер является компонентом Singleton). Конечно, безопасность потока должна поддерживаться при вызове метода, но обычно механизм сервлетов избавляет от необходимости что-то синхронизировать, потому что запрос выполняется внутри потока. Таким образом, во время вызова любого аннотированного метода @RequestMapping весь стек вызовов выполняется в одном потоке. В корне это происходит из методов service-do (Get, Post..) сервлета, а затем действует карта обработчиков, которую создает Spring (см., Например, http://www.studytrails.com/frameworks/spring/spring-mvc-handler-mappings/ http://technicalstack.com/dispatcher-servlethandlermapping-controller/).Spring вызывает метод обработки из карты обработчиков после разрешения URL. Других хитростей нет. Так что подумайте, вы работаете внутри метода doPost (...), например, DispatchServlet. Безопасен ли поток сервлетов? Нет грубых. Можете ли вы сделать это потокобезопасным - да, использовать блокировки, синхронизироваться, что еще и сделать ваш сервлет узким местом! Точно то же самое касается контроллера. DoGet/Post/what еще метод Servlet имеет в основном функциональную модель, все данные находятся в объекте HttpServletRequest. Аналогичным образом следует использовать в Controller object- используемые классы данных и стек вместо полей. Вы можете синхронизировать доступ к ним, но заплатив цену за узкое место. Конечно, вы можете использовать атомистику, так ли это нужно? Если вам нужно сохранить какое-либо состояние во время сеанса, вы можете использовать @Scope ("session") после @Controller или (для одноэлементного контроллера) метод-обработчик с сигнатурой (..., HttpSession), оба из которых имеют свои преимущества и недостатки. Но обратите внимание, что вы создали дополнительные расходы на процессор и сборку.  В любом случае, вы несете ответственность за безопасность потоков в контроллере, когда хотите использовать поля и выйти из концепции отсутствия состояния. Обычно кэш (например, redis) предпочтителен для хранения состояния клиента. По крайней мере, вы можете восстановить состояние, когда произошел сбой. Контроллеры с состоянием вне области сеанса в основном не имеют причин.