对于具有纯 Java 配置的 Spring webapp,拥有 2 个不同的上下文是否有意义?

For a Spring webapp with pure Java config, does it make sense to have 2 distinct contexts?

我是 Spring Java 配置的新手,想知道一些事情。

传统上 Spring 网络应用程序有 2 个不同的上下文,根应用程序上下文和调度程序 servlet 上下文。根上下文基本上包含服务层(持久性配置,如 JPA 和数据访问层)和包含所有 MVC 和其他与 Web 相关的东西的 servlet 上下文。

Web 上下文继承自根上下文,因此 Web 组件可以访问根上下文中的 bean,但相反。

通过使用 XML-less 配置和 org.springframework.web.WebApplicationInitializer 的现代方法,拥有 2 个不同的上下文是否仍然有意义?

只用一些带注释的 @Configuration 类 按层重新组合 bean(例如,一个用于数据访问层,一个用于服务层,一个用于 Web 层)并加载所有 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("/");
    }
}

对于一个简单的 web 应用程序(单个 maven 模块),第二种方法是否带来了任何平衡额外复杂性的具体好处?最佳做法是什么?

你是在征求意见,离意见不远了。这个答案是对Spring哲学的理解。

Spring 允许 对非 MVC 部分和 MVC 部分和 使用不同的上下文建议 这样做,因为关注点分离 (*) 被认为是一种好的做法。它从不强迫开发人员这样做。

可以 将所有内容放在 java 配置中的单个上下文中,与使用 XML

完全相同

由您决定该伪规则(2 个上下文)是否与您的应用程序相关。如果您以后可以从 Spring MVC 转移到另一个框架,它 相关的。如果您在一个大型组织中工作,其中不同的开发人员可以处理 MVC 部分和非 MVC 部分,那么它 相关的。如果它是一个非常简单的应用程序,只有一个开发人员,并且很少有预期的改进,那么您当然可以将 最佳实践 与简单性进行交换。

规则只是指南,开发者必须知道什么时候必须遵守,什么时候可以忽略。这实际上取决于一般背景、项目规模、组织和一般经验。

(*) 将模型部分(服务和持久性)与 VC 部分(用户界面)分开被认为是好的,因为:

  • 您可以(理论上)在保留模型部分的同时更改 UI 部分(从传统 WebApp 迁移到胖客户端只是将 UI 更改为最小的 RESTfull 接口)
  • 您可以尽可能少地坚持开发和测试不同的层
  • 您可以在模型和 ViewController 部分拥有不同的团队,并且职责明确分离
  • 公司规则可能会强制执行

1) 每个应用程序一个上下文可能只是单例反模式的另一种转世。基本上它是你的东西的单一范围,当你有很多 beans 时,尤其是不明确的依赖关系,它很快就会导致问题。

2) 您可以根据需要实时构建和销毁子上下文,从而做很多花哨的事情,从而减少对长寿命对象、事件层次结构等的关注(尽管简单的不需要这些东西)网络应用)