Spring Boot 带有多个 DispatcherServlet,每个都有自己的 @Controllers

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30670327/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 00:37:12  来源:igfitidea点击:

Spring Boot with multiple DispatcherServlet, each having their own @Controllers

springspring-mvcservletsspring-bootspring-4

提问by Benjamin M

Basically I want to split my application into 2 parts. Each part has it's own security stuff and own @Controllers. The @Servicesshould be accessible from both parts.

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

So I thought, I should get 2 DispatcherServlet. One listening to /admin/*and the second listening to everything else ( /). Each of those will have its own AnnotationConfigWebApplicationContextso I can have separate component scan for the @Controllers.

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

And because Spring Boot provides one DispatcherServletlistening on /out of the box, I thought, I can just add a second one:

因为 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;
    }
}

The MyConfig2class, only has @Configurationand @ComponentScan. Within the same package is a @Controller.

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

When starting the application, I can see, that the second servlet mapping is getting registered, but the @Controlleris not. Additionally I can now access all@Controllersfrom /and/admin.

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



Any idea how I can get this working?

知道如何让这个工作吗?

回答by Benjamin M

I got it working somehow!

我以某种方式让它工作了!

Here's my Package Layout:

这是我的包布局:

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:

应用程序.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;
    }
}
  • The excludedoes prevent Spring Boot from creating its own DispatcherServletwith /mapping. You can remove that line, if you want that mapping or define your own.
  • You can add servletRegistrationBean.setLoadOnStartup(1)if you want to have your Servlets initialized on application start. Else it will wait for the first request for that servlet.
  • It's important to set servletRegistrationBean.setName(...), else the servlets will override each other.
  • exclude确实会阻止 Spring Boot 创建自己DispatcherServlet/映射。如果您想要该映射或定义您自己的映射,您可以删除该行。
  • servletRegistrationBean.setLoadOnStartup(1)如果您希望在应用程序启动时初始化 Servlet,您可以添加。否则,它将等待对该 servlet 的第一个请求。
  • 设置 很重要servletRegistrationBean.setName(...),否则 servlet 将相互覆盖。

FooConfig.java & BarConfig.java:

FooConfig.java 和 BarConfig.java:

@Configuration @ComponentScan @EnableWebMvc
public class FooConfig { }
  • @EnableWebMvcwill enable the component scan. Without it, it won't find the @Controllerclass.
  • @EnableWebMvc将启用组件扫描。没有它,它就找不到@Controller类。

The Controller and Service codeis not important. You just have to know, that if you have @RequestMapping("/foo")inside FooController, the request must be GET /foo/foobecause the Servlet's URL mapping is /foo/*. It's not possible to call the URL GET /foobecause the Servlet URL mapping needs a /at the end of its path (in other words: GET /foowill look for a Servlet with /mapping!), though @RequestMapping("")must be called via GET /foo/. And of course it was not possible to use /fooor /foo*as Servlet mapping (or I just did not find the correct settings for that)

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

Scope:The Controllers can't seeeach other, though it's notpossible to @Autowiredthem in each other. Also the Service can't @Autowiredany of the Controllers. Butthe Controllers can @Autowiredthe Service.

适用范围:该控制器无法看到对方,虽然它没有可能@Autowired他们彼此。此外,服务不能使用@Autowired任何控制器。但是控制器可以@Autowired服务。

Though it's a classical parent child context hierarchy.

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

The only "bad" thing is, that we need @EnableMvcConfigand don't get the auto configured sugar from Spring boot within the context. The parent context is getting auto configured. I put some database stuff within the application.propertiesand did a query inside MyServicewhich got called by FooControllerand it worked flawlessly! :)

唯一“不好”的事情是,我们需要@EnableMvcConfig并且不从上下文中的 Spring boot 获取自动配置的糖。父上下文正在自动配置。我在application.properties里面放了一些数据库的东西,并在里面做了一个查询,MyService它被调用了FooController,它工作得很好!:)

I hope this may help some people!

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