Для веб-приложения Spring с чистой конфигурацией Java имеет ли смысл иметь 2 разных контекста?

Я новичок в конфигурации Spring Java, и мне что-то интересно.

Традиционно веб-приложения Spring имели 2 разных контекста: контекст корневого приложения и контекст сервлета диспетчера. Корневой контекст содержит в основном все, вплоть до сервисного уровня (конфигурация персистентности, такая как JPA и уровень доступа к данным), и контекст сервлета, содержащий все MVC и другие вещи, связанные с сетью.

Веб-контекст наследуется от корневого контекста, поэтому веб-компоненты имеют доступ к компонентам в корневом контексте, но не наоборот.

С современным подходом, использующим конфигурацию без XML и org.springframework.web.WebApplicationInitializer, имеет ли смысл иметь 2 разных контекста?

Казалось бы, проще иметь несколько аннотированных классов @Configuration, перегруппировывающих bean-компоненты по уровням (например, один для уровня доступа к данным, один для сервисного уровня, один для веб-слоя) и загружать их все в одном контексте, например:

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {

        // Create the dispatcher servlet's Spring application context
        AnnotationConfigWebApplicationContext dispatcherServletContext = new AnnotationConfigWebApplicationContext();
        dispatcherServletContext.register(MyPersistenceConfig.class, MyServicesConfig.class, MyMvcConfig.class);

        // Register and map the dispatcher servlet
        ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherServletContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }

}

Однако я видел примеры, когда корневой контекст все еще создается, а его жизненный цикл управляется с помощью org.springframework.web.context.ContextLoaderListener, например:

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {

        // Create the 'root' Spring application context
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(MyPersistenceConfig.class, MyServicesConfig.class);

        // Manage the lifecycle of the root application context
        container.addListener(new ContextLoaderListener(rootContext));

        // Create the dispatcher servlet's Spring application context
        AnnotationConfigWebApplicationContext dispatcherServletContext = new AnnotationConfigWebApplicationContext();
        dispatcherServletContext.register(MyMvcConfig.class);

        // Register and map the dispatcher servlet
        ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherServletContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }
}

Для простого веб-приложения (один модуль maven) дает ли второй подход какие-либо конкретные преимущества, которые уравновешивают дополнительную сложность? Какова наилучшая практика?


person Pierre Henry    schedule 08.07.2015    source источник


Ответы (2)


Вы просите советов, но это недалеко от мнений. Этот ответ — то, что я понял из философии Spring.

Spring позволяет использовать разные контексты для части, отличной от MVC, и для части MVC, и рекомендует это делать, поскольку разделение ответственности (*) считается хорошей практикой. Это никогда не заставляет разработчика делать это.

Вы можете поместить все в один контекст в конфигурации Java, точно так же, как вы можете сделать это с XML.

Вам решать, применимо ли это псевдоправило (2 контекста) к вашему приложению. Если позже вы сможете перейти с Spring MVC на другую платформу, это актуально. Если вы работаете в крупной организации, где над частью MVC и над частью, отличной от MVC, могут работать разные разработчики, это актуально. Если это действительно простое приложение с одним единственным разработчиком и небольшими ожидаемыми изменениями, вы, безусловно, можете заменить лучшие практики на простоту.

Правила — это всего лишь рекомендации, и разработчики должны знать, когда им нужно следовать, а когда их можно игнорировать. И это действительно зависит от общего контекста, размера проекта, организации и общего опыта.

(*) отделение части модели (сервис и постоянство) от части VC (пользовательский интерфейс) считается хорошим, потому что:

  • вы можете (теоретически) изменить часть пользовательского интерфейса, сохранив при этом часть модели (миграция с традиционного веб-приложения на толстый клиент — это просто изменение пользовательского интерфейса на минимальный интерфейс RESTfull)
  • вы можете разрабатывать и тестировать различные слои с минимально возможной приверженностью
  • у вас могут быть разные команды для частей Model и ViewController с четким разделением ответственности
  • это может быть обеспечено корпоративными правилами
person Serge Ballesta    schedule 08.07.2015
comment
Спасибо Сережа за общий ответ. Но я надеялся на что-то более похожее на список конкретных преимуществ, которые можно получить за счет отдельных контекстов, например, я могу думать о том, что вы можете создавать модульные тесты для своего сервисного уровня независимо от веб-фреймворка или, как вы упомянули, вы можете легче переключать веб-фреймворки в будущем. Если вы отредактируете свой вопрос в этом стиле, я приму ваш ответ. - person Pierre Henry; 08.07.2015

1) Один контекст для каждого приложения может стать еще одной реинкарнацией антипаттерна Singleton. По сути, это единая область действия для ваших вещей, и когда у вас много bean-компонентов, особенно неоднозначных зависимостей, это быстро приводит к проблемам.

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

person xeye    schedule 09.07.2015