Spring Bootの@ServletComponentScanアノテーション

1.概要

この記事では、新しい @ServletComponentScan アノテーションについて説明します。 Spring Boot.

目的は、以下の Servlet 3.0 アノテーションをサポートすることです。

  • javax.servlet.annotation.WebFilter

  • javax.servlet.annotation.WebListener

  • javax.servlet.annotation.WebServlet

@ WebServlet @ WebFilter 、および @ WebListener のアノテーション付きクラスは、 @ Configuration クラスに @ ServletComponentScan をアノテーションしてパッケージを指定することで、自動的に埋め込み Servlet コンテナに登録できます。

リンク内の @ WebServlet の基本的な使用法を紹介しました。/intro-to-servlets[Javaサーブレットの紹介]およびリンク内の @ WebFilter の基本的な使い方:/intercepting-filter-pattern-in-java]。 @ WebListener については、リンク:/httpsessionlistener with metrics[この記事]でのぞき見をすることができます。これは、Webリスナーの典型的な使用例を示しています。

2. Servlets Filters 、および Listeners

@ ServletComponentScan に飛び込む前に、 @ ServletComponentScan が登場する前に、アノテーション @ WebServlet @ WebFilter 、および @ WebListener がどのように使用されていたかを見てみましょう。

2.1. @ WebServlet

それでは、最初に GET 要求を処理して応答する Servlet を定義します。

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        try {
            response
              .getOutputStream()
              .write("hello");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

2.2. @ WebFilter

次に、ターゲット「 "/hello" への要求をフィルター処理し、出力の先頭に "filtering" を付加します。

@WebFilter("/hello")
public class HelloFilter implements Filter {

   //...
    @Override
    public void doFilter(
      ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
      throws IOException, ServletException {
        servletResponse
          .getOutputStream()
          .print("filtering ");
        filterChain.doFilter(servletRequest, servletResponse);
    }
   //...

}

2.3. @ WebListener

最後に、 ServletContext にカスタム属性を設定するリスナーです。

@WebListener
public class AttrListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        servletContextEvent
          .getServletContext()
          .setAttribute("servlet-context-attr", "test");
    }
   //...
}

2.4. Servlet コンテナにデプロイする

単純なWebアプリケーションの基本コンポーネントを構築したので、それをパッケージ化して Servlet コンテナにデプロイします。パッケージ化されたwarファイルを Jetty Tomcat 、または Servlet 3.0をサポートする任意の Servlet コンテナに展開することで、各コンポーネントの動作を簡単に検証できます。

3. Spring Boot @ ServletComponentScan を使う

私たちは何の設定もせずにほとんどの Servlet コンテナでそれらのアノテーションを使うことができるのであなたは不思議に思うかもしれません、なぜ我々は @ ServletComponentScan を必要としますか?問題は組み込みの Servlet コンテナにあります。

組み込みコンテナは @ WebServlet @ WebFilter 、および @ WebListener アノテーション、 Spring Boot、 組み込みコンテナに大きく依存していないため、これらの3つのアノテーションを使用するいくつかの依存jarをサポートするためにこの新しいアノテーションを導入しました。

詳細な議論はhttps://github.com/spring-projects/spring-boot/issues/2290[このGithubに関する問題]にあります。

3.1. Mavenの依存関係

@ ServletComponentScan を使用するには、バージョン1.3.0以降の Spring Boot が必要です。 spring-boot-starter-parent の最新バージョンを追加しましょう。 およびhttps://search.maven.org/classic/#artifactdetails%7Corg.springframework.boot%7Cspring-boot-starter-web%7C1.5.1.RELEASE%7Cjar[ spring-boot-starter-web ]を pom に:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.1.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>1.5.1.RELEASE</version>
    </dependency>
</dependencies>

3.2. @ ServletComponentScan を使用する

Spring Boot アプリはとてもシンプルです。 @ WebFilter @ WebListener 、および @ WebServletのスキャンを有効にするために @ ServletComponentScan__を追加します。

@ServletComponentScan
@SpringBootApplication
public class SpringBootAnnotatedApp {

    public static void main(String[]args) {
        SpringApplication.run(SpringBootAnnotatedApp.class, args);
    }

}

以前のWebアプリケーションを変更しなくても動作します。

@Autowired private TestRestTemplate restTemplate;

@Test
public void givenServletFilter__whenGetHello__thenRequestFiltered() {

    ResponseEntity<String> responseEntity =
      restTemplate.getForEntity("/hello", String.class);

    assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
    assertEquals("filtering hello", responseEntity.getBody());
}
@Autowired private ServletContext servletContext;

@Test
public void givenServletContext__whenAccessAttrs__thenFoundAttrsPutInServletListner() {

    assertNotNull(servletContext);
    assertNotNull(servletContext.getAttribute("servlet-context-attr"));
    assertEquals("test", servletContext.getAttribute("servlet-context-attr"));
}

3.3. スキャンするパッケージを指定する

デフォルトでは、 @ ServletComponentScan はアノテーション付きクラスのパッケージからスキャンします。どのパッケージをスキャンするかを指定するために、その属性を使用できます。

  • basePackages

  • basePackageClasses

デフォルトの value 属性は、 basePackages のエイリアスです。

SpringBootAnnotatedApp com.baeldung.annotation パッケージの下にあり、上記のWebアプリケーションで作成された com.baeldung.annotation.components パッケージ内のクラスをスキャンするとします。次の構成は同じです。

@ServletComponentScan
@ServletComponentScan("com.baeldung.annotation.components")
@ServletComponentScan(basePackages = "com.baeldung.annotation.components")
@ServletComponentScan(
  basePackageClasses =
    {AttrListener.class, HelloFilter.class, HelloServlet.class})

4.フードの下

@ ServletComponentScan アノテーションはhttps://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/によって処理されます。 web/servlet/ServletComponentRegisteringPostProcessor.java[ ServletComponentRegisteringPostProcessor ]。

@ WebFilter @ WebListener 、および @ WebServlet アノテーションの指定されたパッケージをスキャンした後、https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-bootのリスト/src/main/java/org/springframework/boot/web/servlet/ServletComponentHandler.java[ ServletComponentHandlers ]はそれらの注釈属性を処理し、スキャンされたBeanを登録します。

class ServletComponentRegisteringPostProcessor
  implements BeanFactoryPostProcessor, ApplicationContextAware {

    private static final List<ServletComponentHandler> HANDLERS;

    static {
        List<ServletComponentHandler> handlers = new ArrayList<>();
        handlers.add(new WebServletHandler());
        handlers.add(new WebFilterHandler());
        handlers.add(new WebListenerHandler());
        HANDLERS = Collections.unmodifiableList(handlers);
    }

   //...

    private void scanPackage(
      ClassPathScanningCandidateComponentProvider componentProvider,
      String packageToScan){
       //...
        for (ServletComponentHandler handler : HANDLERS) {
            handler.handle(((ScannedGenericBeanDefinition) candidate),
              (BeanDefinitionRegistry) this.applicationContext);
        }
    }
}

official Javadoc で述べられているように、** @ ServletComponentScan 注釈はデフォルトでは Spring Boot に付属しているものです。

5.まとめ

この記事では、 @ ServletComponentScan と、それがどのアノテーションに依存するアプリケーションをサポートするためにどのように使用できるかを紹介しました。

@ WebServlet @ WebFilter @ WebListener

例とコードの実装はhttps://github.com/eugenp/tutorials/tree/master/spring-boot/[GitHubプロジェクト]にあります。