具有多个分派器的Spring Java Config
问题内容:
我现在有一些Spring的经验,也有一些纯Java配置的Web应用程序在使用中。但是,这些通常基于安静的简单设置:
- 服务/存储库的应用程序配置
- 一个调度程序(和某些控制器)的调度程序配置
- (可选)弹簧安全性以确保访问权限
对于我当前的项目,我需要具有不同配置的单独的调度程序上下文。对于基于XML的配置,这不是问题,因为我们有一个专用的ContextLoaderListener,它独立于Dispatcher
Configuration。但是,使用java config,我不确定到目前为止我做的是否还可以;)
这是一个常见的DispatcherConfig:
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new class[]{MyAppConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{MyDispatcherConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/mymapping/*"};
}
@Override
protected String getServletName() {
return "myservlet";
}
}
如前所述,我需要第二个(第三个,…)调度程序和另一个映射(和视图解析器)。因此,我复制了配置并为两个getServletName()添加了一个属性(否则两个都将被命名为“
dispatcher”,这将导致错误)。第二个配置看起来像这样:
public class AnotherWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new class[]{MyAppConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{AnotherDispatcherConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/another_mapping/*"};
}
@Override
protected String getServletName() {
return "anotherservlet";
}
}
当我这样使用它时,启动应用程序会导致ContextLoaderListener出现问题:
java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:277)
...
因此,我从 AbstractAnnotationConfigDispatcherServletInitializer 之一中删除了第二个
MyAppConfig.class 返回, 并且运行正常。但是,这并不是正确的方法;) __
据我了解:所有DispatcherConfig应该在一个
AbstractAnnotationConfigDispatcherServletInitializer中
处理还是应该像我一样将它们分开?我试图在一类中配置它们,但是后来我的配置完全混杂了(所以我认为这不是理想的方式)。
您如何实施这种情况?是否可以在 AbstractAnnotationConfigDispatcherServletInitializer
之外的Java配置中设置 ContextLoaderListener ?还是应该创建仅具有根配置的 DefaultServlet ?如何实现该配置
WebApplicationInitializer 的基本接口? __
问题答案:
Mahesh
C.显示了正确的道路,但是他的实施方式太有限。他的观点是正确的:您不能直接AbstractAnnotationConfigDispatcherServletInitializer
用于多个调度程序servlet。但实施应:
- 创建一个根应用程序上下文
- 给它一个初始配置,并说应该扫描哪些软件包
- 为它添加一个ContextListener到servlet上下文中
- 然后对于每个调度程序servlet
- 创建一个子应用程序上下文
- 给它相同的初始配置和要扫描的软件包
- 使用上下文创建一个DispatcherServlet
- 将其添加到servlet上下文
这是一个更完整的实现:
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// root context
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(RootConfig.class); // configuration class for root context
rootContext.scan("...service", "...dao"); // scan only some packages
servletContext.addListener(new ContextLoaderListener(rootContext));
// dispatcher servlet 1
AnnotationConfigWebApplicationContext webContext1 =
new AnnotationConfigWebApplicationContext();
webContext1.setParent(rootContext);
webContext1.register(WebConfig1.class); // configuration class for servlet 1
webContext1.scan("...web1"); // scan some other packages
ServletRegistration.Dynamic dispatcher1 =
servletContext.addServlet("dispatcher1", new DispatcherServlet(webContext1));
dispatcher1.setLoadOnStartup(1);
dispatcher1.addMapping("/subcontext1");
// dispatcher servlet 2
...
}
这样,您完全可以控制哪个bean在哪个上下文中结束,就像使用XML配置一样。