26.Расскажите про шаблон проектирования Front Controller, как он реализован в Spring?
UNKNOWNПаттерн Front Controller обеспечивает единую точку входа для всех входящих запросов.
Все запросы обрабатываются одним фрагментом кода, который затем может делегировать ответственность за обработку запроса другим объектам приложения. Он также обеспечивает интерфейс для общего поведения, такого как безопасность, интернационализация и передача определенных представлений определенным пользователям.
В Spring в качестве Front Controller выступает DispatcherServlet, все действия проходят через него. Как правило в приложении задаётся только один DispatcherServlet с маппингом “/”, который перехватывает все запросы. Это и есть реализация паттерна Front Controller.
Однако иногда необходимо определить два и более DispatcherServlet-а, которые будут отвечать за свой собственный функционал. Например, чтобы один обрабатывал REST-запросы с маппингом “/api”, а другой обычные запросы с маппингом “/default”. Spring предоставляет нам такую возможность, и для начала нужно понять, что:
- Spring может иметь несколько контекстов одновременно. Одним из них будет корневой контекст, а все остальные контексты будут дочерними.
- Все дочерние контексты могут получить доступ к бинам, определенным в корневом контексте, но не наоборот. Корневой контекст не может получить доступ к бинам дочерних контекстов.
- Каждый дочерний контекст внутри себя может переопределить бины из корневогоконтекста.

Каждый DispatcherServlet имеет свой дочерний контекст приложения. DispatcherServlet по сути является сервлетом (он расширяет HttpServlet), основной целью которого является обработка входящих веб-запросов, соответствующих настроенному шаблону URL. Он принимает входящий URI и находит правильную комбинацию контроллера и вида.
Веб-приложение может определять любое количество DispatcherServlet-ов. Каждый из них будет работать в своем собственном пространстве имен, загружая свой собственный дочерний WebApplicationContext (на рисунке - Servlet WebApplicationContext) с вьюшками, контроллерами и т.д. Например, когда нам нужно в одном Servlet WebApplicationContext определить обычные контроллеры, а в другом REST-контроллеры.
WebApplicationContext расширяет ApplicationContext (создаёт и управляет бинами и т.д.), но помимо этого он имеет дополнительный метод getServletContext(), через который у него есть возможность получать доступ к ServletContext-у.
ContextLoaderListener создает корневой контекст приложения (на рисунке - Root WebApplicationContext) и будет использоваться всеми дочерними контекстами, созданными всеми DispatcherServlet. Напомню, что корневой контекст приложения будет общим и может быть только один. Root WebApplicationContext содержит компоненты, которые видны всем дочерним контекстам, такие как сервисы, репозитории, компоненты инфраструктуры и т.д.
После создания корневого контекста приложения он сохраняется в ServletContext как атрибут, имя которого:
WebApplicationContext.class.getName() + \".ROOT\"
Чтобы из контроллера любого дочернего контекста обратиться к корневому контексту приложения, мы можем использовать класс WebApplicationContextUtils, содержащий статические методы:
@Autowired
ServletContext context;
ApplicationContext ac =
WebApplicationContextUtils.getWebApplicationContext(context);
if(ac == null){
return \"root application context is null\";
}
ContextLoaderListener vs DispatcherServlet
- ContextLoaderListener создает корневой контекст приложения.
- Каждый DispatcherServlet создаёт себе один дочерний контекст.
- Дочерние контексты могут обращаться к бинам, определенным в корневом контексте.
- Бины в корневом контексте не могут получить доступ к бинам в дочерних контекстах (напрямую).
- Все контексты добавляются в ServletContext.
- Мы можем получить доступ к корневому контексту, используя класс WebApplicationContextUtils.

Предыдущий вопрос: 25. Что такое ViewResolver?
Следующий вопрос: 27.Чем отличаются Model, ModelMap и ModelAndView?
Все вопросы по теме: список
Все темы: список
Вопросы/замечания/предложения/нашли ошибку: напишите мне