Spring Bootの@ServletComponentScanアノテーション
1. 概要
この記事では、Spring Boot.の新しい@ServletComponentScanアノテーションについて説明します。
目的は、次のServlet 3.0アノテーションをサポートすることです。
-
javax.servlet.annotation.WebFilter
-
javax.servlet.annotation.WebListener
-
javax.servlet.annotation.WebServlet
@WebServlet、@WebFilter、および@WebListenerアノテーション付きクラスは、@Configurationクラスに@ServletComponentScanアノテーションを付けて指定することにより、埋め込みServletコンテナーに自動的に登録できます。パッケージ。
Introduction to Java Servletsの@WebServletとIntroduction to Intercepting Filter Pattern in Javaの@WebFilterの基本的な使用法を紹介しました。 @WebListenerの場合、Webリスナーの一般的な使用例を示すthis articleを確認できます。
2. Servlets、Filters、およびListeners
@ServletComponentScanに飛び込む前に、@ServletComponentScanが機能する前に、アノテーション(@WebServlet、@WebFilter、@WebListener)がどのように使用されたかを見てみましょう。
2.1. @WebServlet
次に、最初にGETリクエストを処理し、“hello”に応答する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");
}
//...
}
3. Spring Bootで@ServletComponentScanを使用する
ほとんどのServletコンテナーでこれらの注釈を構成なしで使用できるので、なぜ@ServletComponentScanが必要なのか疑問に思われるかもしれません。 問題は、埋め込まれたServletコンテナにあります。
埋め込みコンテナは@WebServlet、@WebFilter、および@WebListenerアノテーションをサポートしていないため、Spring Boot,は埋め込みコンテナに大きく依存しており、この新しいアノテーション@ServletComponentScanをこれらの3つのアノテーションを使用するいくつかの依存jarをサポートします。
詳細な説明はthis issue on Githubにあります。
3.1. Mavenの依存関係
@ServletComponentScanを使用するには、バージョン1.3.0以降のSpring Bootが必要です。 最新バージョンのspring-boot-starter-parentとspring-boot-starter-webをpomに追加しましょう。
org.springframework.boot
spring-boot-starter-parent
1.5.1.RELEASE
org.springframework.boot
spring-boot-starter-web
1.5.1.RELEASE
3.2. @ServletComponentScanの使用
Spring Bootアプリは非常にシンプルです。 @ServletComponentScanを追加して、@WebFilter、@WebListener、および@WebServlet:のスキャンを有効にします
@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 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.example.annotationの下にあり、上記のWebアプリケーションで作成されたパッケージcom.example.annotation.componentsのクラスをスキャンするとします。次の構成は、同等です。
@ServletComponentScan
@ServletComponentScan("com.example.annotation.components")
@ServletComponentScan(basePackages = "com.example.annotation.components")
@ServletComponentScan(
basePackageClasses =
{AttrListener.class, HelloFilter.class, HelloServlet.class})
4. フードの下
@ServletComponentScanアノテーションはServletComponentRegisteringPostProcessorによって処理されます。 指定されたパッケージで@WebFilter、@WebListener、および@WebServletアノテーションをスキャンした後、ServletComponentHandlersのリストがそれらのアノテーション属性を処理し、スキャンされたBeanを登録します。
class ServletComponentRegisteringPostProcessor
implements BeanFactoryPostProcessor, ApplicationContextAware {
private static final List HANDLERS;
static {
List 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 annotation only works in embedded Servlet containersで述べたように、これはデフォルトでSpring Bootに付属しています。
5. 結論
この記事では、@ServletComponentScanと、それを使用して、注釈(@WebServlet、@WebFilter、@WebListener)のいずれかに依存するアプリケーションをサポートする方法を紹介しました。
例とコードの実装はin the GitHub projectにあります。