web-dev-qa-db-ja.com

それぞれが独自の@Controllerを持つ複数のDispatcherServletを使用したSpring Boot

基本的に、アプリケーションを2つの部分に分割します。各部分には、独自のセキュリティと独自の@Controllersがあります。 @Servicesは、両方の部分からアクセスできる必要があります。

だから、2 DispatcherServletを取得する必要があると思いました。 1つは/admin/*をリッスンし、2つ目は他のすべてをリッスンします(/)。これらはそれぞれ独自のAnnotationConfigWebApplicationContextを持つため、@Controllersの個別のコンポーネントスキャンを実行できます。

また、Spring BootはDispatcherServletをすぐに/でリッスンするので、2つ目を追加できると思いました。

@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があります。

アプリケーションを起動すると、2番目のサーブレットマッピングが登録されていることがわかりますが、@Controllerは登録されていません。さらに、@Controllersからall/にアクセスできるようになりましたおよび/admin


これをどのように機能させることができますか?

18
Benjamin M

なんとか機能しました!

これが私のパッケージレイアウトです。

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を作成することを防ぎます。マッピングが必要な場合、または独自に定義する場合は、その行を削除できます。
  • アプリケーションの起動時にサーブレットを初期化する場合は、servletRegistrationBean.setLoadOnStartup(1)を追加できます。それ以外の場合は、そのサーブレットの最初のリクエストを待ちます。
  • servletRegistrationBean.setName(...)を設定することが重要です。そうしないと、サーブレットが互いにオーバーライドします。

FooConfig.JavaおよびBarConfig.Java:

@Configuration @ComponentScan @EnableWebMvc
public class FooConfig { }
  • @EnableWebMvcは、コンポーネントスキャンを有効にします。これがないと、@Controllerクラスが見つかりません。

コントローラーおよびサービスコードは重要ではありません。 FooController内に@RequestMapping("/foo")がある場合、サーブレットのURLマッピングはGET /foo/fooであるため、リクエストは/foo/*でなければなりません。サーブレットURLマッピングのパスの最後にGET /fooが必要なため、URL /を呼び出すことはできません(つまり、GET /fooは、/マッピングでサーブレットを探します!)。ただし、@RequestMapping("")GET /foo/。そしてもちろん、/fooまたは/foo*をサーブレットマッピングとして使用することはできませんでした(または、そのための正しい設定が見つかりませんでした)

Scope:コントローラーは相互に参照することはできませんが、お互いに@Autowiredすることは可能です not 。また、サービスはどのコントローラも@Autowiredできません。 しかし/コントローラーはサービスを@Autowiredできます。

それは古典的な親子コンテキスト階層ですが。

唯一の「悪い」ことは、@EnableMvcConfigが必要であり、コンテキスト内のSpringブートから自動構成されたシュガーを取得しないことです。親コンテキストは自動構成されています。私はapplication.properties内にいくつかのデータベースを配置し、MyServiceによって呼び出されたFooController内でクエリを実行しましたが、問題なく動作しました! :)

これが一部の人々に役立つことを願っています!

36
Benjamin M