具有多个 DispatcherServlet 的 Spring Boot,每个 DispatcherServlet 都有自己的 @Controller

Posted

技术标签:

【中文标题】具有多个 DispatcherServlet 的 Spring Boot,每个 DispatcherServlet 都有自己的 @Controller【英文标题】:Spring Boot with multiple DispatcherServlet, each having their own @Controllers 【发布时间】:2015-08-20 15:04:36 【问题描述】:

基本上我想将我的应用程序分成两部分。每个部分都有自己的安全性内容并拥有@Controllers。 @Services 应该可以从两个部分访问。

所以我想,我应该得到 2 个DispatcherServlet。一个听/admin/*,第二个听其他所有内容(/)。每个都有自己的AnnotationConfigWebApplicationContext,所以我可以对@Controllers 进行单独的组件扫描。

而且由于 Spring Boot 提供了一个开箱即用的 DispatcherServlet 监听 /,我想,我可以添加第二个:

@Configuration
public class MyConfig 
    @Bean(name="myDS")
    public DispatcherServlet myDS(ApplicationContext applicationContext) 
        AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
        webContext.setParent(applicationContext);
        webContext.register(MyConfig2.class);
        // webContext.refresh();
        return new DispatcherServlet(webContext);
    

    @Bean
    public ServletRegistrationBean mySRB(@Qualifier("myDS") DispatcherServlet dispatcherServlet) 
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet);
        servletRegistrationBean.addUrlMappings("/admin/*");
        servletRegistrationBean.setName("adminServlet");
        return servletRegistrationBean;
    

MyConfig2 类,只有@Configuration@ComponentScan。在同一个包中是一个@Controller

启动应用程序时,我可以看到第二个 servlet 映射正在注册,但 @Controller 没有注册。此外,我现在可以从/ /admin 访问all @Controllers


知道我怎样才能让它工作吗?

【问题讨论】:

【参考方案1】:

我让它以某种方式工作!

这是我的包装布局:

test.foo.
         FooConfig.java
         FooController.java
test.bar.
         BarConfig.java
         BarController.java
test.app.
         Application.java
         MyService.java
src/main/resources/application.properties

Application.java:

@SpringBootApplication(exclude=DispatcherServletAutoConfiguration.class)
public class Application 
    public static void main(String[] args) throws Exception 
        SpringApplication.run(Application.class, args);
    
    @Bean
    public ServletRegistrationBean foo() 
        DispatcherServlet dispatcherServlet = new DispatcherServlet();   
        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
        applicationContext.register(FooConfig.class);
        dispatcherServlet.setApplicationContext(applicationContext);
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/foo/*");
        servletRegistrationBean.setName("foo");
        return servletRegistrationBean;
    
    @Bean
    public ServletRegistrationBean bar() 
        DispatcherServlet dispatcherServlet = new DispatcherServlet();
        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
        applicationContext.register(BarConfig.class);
        dispatcherServlet.setApplicationContext(applicationContext);
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/bar/*");
        servletRegistrationBean.setName("bar");
        return servletRegistrationBean;
    

exclude 确实阻止 Spring Boot 使用 / 映射创建自己的 DispatcherServlet。如果您想要该映射或定义您自己的映射,您可以删除该行。 如果您希望在应用程序启动时初始化您的 Servlet,您可以添加 servletRegistrationBean.setLoadOnStartup(1)。否则它将等待对该 servlet 的第一个请求。 设置 servletRegistrationBean.setName(...) 很重要,否则 servlet 将相互覆盖。

FooConfig.java & BarConfig.java:

@Configuration @ComponentScan @EnableWebMvc
public class FooConfig  
@EnableWebMvc 将启用组件扫描。没有它,它将找不到@Controller 类。

控制器和服务代码并不重要。你只需要知道,如果你在FooController 中有@RequestMapping("/foo"),那么请求必须是GET /foo/foo,因为Servlet 的URL 映射是/foo/*。不可能调用 URL GET /foo,因为 Servlet URL 映射需要在其路径末尾有一个 /(换句话说:GET /foo 将寻找一个具有 / 映射的 Servlet!),尽管 @987654340 @ 必须通过 GET /foo/ 调用。当然不可能使用 /foo/foo* 作为 Servlet 映射(或者我只是没有找到正确的设置)

范围:控制器不能看到彼此,尽管@Autowired 彼此之间是不可能。此外,服务不能@Autowired 任何控制器。 但是控制器可以@Autowired服务。

虽然它是一个经典的父子上下文层次结构。

唯一“坏”的事情是,我们需要@EnableMvcConfig 并且不要在上下文中从 Spring 引导中获取自动配置的糖。父上下文正在自动配置。我在application.properties 中放入了一些数据库内容,并在MyService 中进行了查询,该查询被FooController 调用,并且运行完美! :)

我希望这可以帮助一些人!

【讨论】:

感谢您的回答。真的很有帮助。我还有一个挑战要克服。如何对 /foo 端点进行身份验证+授权(基于数据库),但仅对 /bar 端点进行身份验证?我有一个来自这里的配置[0]。 ***.com/questions/36909226/… 感谢本杰明,我正在努力解决同样的问题,并在阅读您的答案后发现需要 @EnableMvcConfig。 感谢您的详尽解释!它帮助我解决了两个不同的问题。我的意思是用“这行得通:”加上没有解释的代码位来自我回答是很常见的...... 为什么我们需要 FooConfig.java 因为它是空类。 @DHARMENDRASINGH FooConfig.java 有注解会导致 Spring 扫描组件、启用 Spring Web MVC 等。

以上是关于具有多个 DispatcherServlet 的 Spring Boot,每个 DispatcherServlet 都有自己的 @Controller的主要内容,如果未能解决你的问题,请参考以下文章

Spring-DispatcherServlet说明

前置控制器一DispatcherServlet

springmvc的工作原理,简单的概括一下

springmvc执行流程

springmvc执行流程

springmvc执行流程