Spring Framework. Общий контекст (root-context.xml) и контекст сервлета (appServlet/servlet-context.xml).

При разработке веб приложений на Spring всегда описывается как минимум два контекста. Один (root-context.xml) — это общий, расшаренный контекст, содержащий бины, которые будут использоваться всеми сервлетами приложения. В web.xml загрузка этого контекста описывается обычно так:

Второй — это контекст самого сервлета. Сервлетов в одном приложении может быть несколько. В web.xml можно задавать их порядок загрузки, если нужно. Загрузка контекста сервлета указывается в web.xml так:

В примере, приведённом выше xml описание контекста сервлета находится в /WEB-INF/spring/appServlet/servlet-context.xml, а load-on-startup — описывает что он будет загружаться первым. Сервлет будет отвечать на запросы по пути <наш_сайт>/<имя_приложения/war_файла>/site/**.

При желании мы можем описать подобным же образом второй сервлет:

Каждый сервлет может содержать разное описание инициализаций Spring MVC, локалей, тем, диспетчеров представлений и прочего.

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

Так вот, правильное разделение должно быть такое.

Общий или корневой контекст (root-context.xml) должен содержать:

  1. Бин dataSource.
  2. Бины слоя доступа к данным и сервисов.
  3. Инициализация транзакции. Менеджер транзакций и tx:annotation-driven должен находится здесь. Контейнер менеджеров сущностей EntityManagerFactory также должен описываться здесь.
  4. Spring Security. Всё описание должно располагаться здесь.

Контекст сервлета (servlet-context.xml) должен содержать:

  1.  Инициализация Spring MVC (mvc:annotation-driven).
  2. Все бины контроллеров сервлета.
  3. Бины локализации: messageSource, localeResolver.
  4. Бины тем представлений: themeSource, themeResolver.
  5. Обработчик представлений и всё, что связано непосредственно с пользовательским вводов/выводом.

Также нужно иметь в виду, что бины, объявленные в корневой или общем (root-context.xml) контексте не имеют доступа к бинам, описанным в контекстах сервлетов, но бины, описанные в контекстах сервлетов имеют доступ к бинам в общем контексте.

Из этого вытекают следующие ограничения:

  1. Поскольку tx:annotation-driven описан в root-context.xml, то аннотация @Transactional может использоваться только для сервисов и слоя доступа к данным. Не используйте его для контроллеров. Это всё равно не будет иметь никакого эффекта. Да и вообще, контроллер не должен заниматься транзакциями и бизнес-логикой, это не его обязанность. Он должен принять данные от пользователя, вызвать слой сервисов и показать результат.
  2. Бин messageSource не доступен для слоя сервисов и слоя доступа к данным. Это тоже вполне верно. Слой сервисов не работает с пользовательским вводом выводом и ничего не отображает ему. Следовательно, ему не нужно знать ничего о локалях и локализованных сообщениях. Вся работа с messageSource должна быть в контроллерах и представлениях.
  3. Spring Security общий для всех сервлетов. То есть, если пользователь авторизовался в одном сервлете, то он автоматически считается авторизованным с той же ролью и тем же Principal в других сервлетах. Но вы можете объявить для каждого сервлета разные формы входа, разные способы аутентификации. Используйте для этого несколько тегов <http pattern=»…».

Spring Framework. Общий контекст (root-context.xml) и контекст сервлета (appServlet/servlet-context.xml).: 2 комментария

  1. А что скажете насчет интерсепторов? Их лучше в корневой или сервлетный контекст?

    1. Полагаю, что в тот же контекст, что и бины, вызовы которых они перехватывают.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *