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 컨테이너에 자동으로 등록 할 수 있습니다 .

Java Servlet 소개에서 @WebServlet 의 기본 사용법을 소개하고 Java 에서 필터 패턴 차단 소개에서 @WebFilter 를 소개했습니다. @WebListener의 경우 웹 수신기의 일반적인 사용 사례를 보여주는이 기사 를 살펴볼 수 있습니다.

2. 서블릿 , 필터리스너

다이빙을하기 전에 @ServletComponentScan :,의는 주석 방법에 대해 살펴 보도록하자 @WebServlet , @WebFilter@WebListener가 이전에 사용 된 @ServletComponentScan은 놀이로 온을.

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"); } //... }

2.4. 서블릿 컨테이너에 배포

이제 간단한 웹 애플리케이션의 기본 구성 요소를 구축 했으므로이를 패키지화하여 Servlet 컨테이너에 배포 할 수 있습니다 . 패키지 된 war 파일을 Jetty , Tomcat 또는 Servlet 3.0 을 지원하는 모든 Servlet 컨테이너 에 배포하여 각 구성 요소의 동작을 쉽게 확인할 수 있습니다 .

3. 스프링 부트 에서 @ServletComponentScan 사용하기

구성없이 대부분의 Servlet 컨테이너 에서 이러한 주석을 사용할 수 있으므로 왜 @ServletComponentScan이 필요한지 궁금것입니다 . 문제는 임베디드 서블릿 컨테이너에 있습니다.

임베디드 컨테이너는 @WebServlet , @WebFilter@WebListener 주석을 지원하지 않기 때문에 임베디드 컨테이너에 크게 의존하는 Spring Boot 는이 3 개의 주석을 사용하는 일부 종속 jar를 지원하기 위해이 새로운 주석 @ServletComponentScan 을 도입했습니다 .

자세한 논의는 Github의 이번 호에서 찾을 수 있습니다.

3.1. Maven 종속성

@ServletComponentScan 을 사용하려면 버전 1.3.0 이상의 Spring Boot 가 필요합니다 . 최신 버전의 spring-boot-starter-parentspring-boot-starter-webpom에 추가해 보겠습니다 .

 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 사용

봄 부팅 응용 프로그램은 매우 간단하다. @WebFilter , @WebListener@WebServlet 스캔을 활성화하기 위해 @ServletComponentScan 을 추가합니다 .

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

이전 웹 응용 프로그램을 변경하지 않고 다음과 같이 작동합니다.

@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

기본 속성의 별칭입니다 basePackages .

우리의 말 SpringBootAnnotatedApp가 패키지 아래 com.baeldung.annotation , 우리는 패키지에서 스캔 클래스에 원하는 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 주석은 의해 처리 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); } } }

공식 Javadoc에서 언급했듯이 @ServletComponentScan 주석은 기본적 으로 Spring Boot 와 함께 제공되는 임베디드 Servlet 컨테이너 에서만 작동합니다 .

5. 결론

이 기사에서 우리는 @ServletComponentScan 과 어노테이션 ( @WebServlet , @WebFilter , @WebListener)에 의존하는 애플리케이션을 지원하는 데 어떻게 사용할 수 있는지 소개 했습니다 .

예제 및 코드의 구현은 GitHub 프로젝트에서 찾을 수 있습니다.