Die Annotation @ServletComponentScan im Spring Boot

1. Übersicht

In diesem Artikel werden wir die neue Annotation @ServletComponentScan in Spring Boot durchgehen .

Ziel ist es, die folgenden Servlet 3.0- Anmerkungen zu unterstützen:

  • javax.servlet.annotation.WebFilter
  • javax.servlet.annotation.WebListener
  • javax.servlet.annotation.WebServlet

Mit @WebServlet , @WebFilter und @WebListener kommentierte Klassen können automatisch in einem eingebetteten Servlet- Container registriert werden, indem @ServletComponentScan in einer @ Configuration- Klasse mit Anmerkungen versehen und die Pakete angegeben werden.

Wir haben die grundlegende Verwendung von @WebServlet in Einführung in Java-Servlets und @WebFilter in Einführung in das Abfangen von Filtermustern in Java eingeführt. Für @WebListener können Sie einen Blick auf diesen Artikel werfen , der einen typischen Anwendungsfall von Weblistenern zeigt.

2. Servlets , Filter und Listener

Vor dem Tauchen in @ServletComponentScan , lassen Sie uns einen Blick darauf , wie die Anmerkungen: @WebServlet , @WebFilter und @WebListener wurden verwendet , um vor @ServletComponentScan ins Spiel kam.

2.1. @ WebServlet

Jetzt definieren wir zuerst ein Servlet , das GET- Anforderungen bedient und "Hallo" antwortet :

@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

Dann ein Filter, der Anforderungen an das Ziel "/ hallo" filtert und der Ausgabe "Filterung" voranstellt :

@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

Schließlich ein Listener, der ein benutzerdefiniertes Attribut in ServletContext festlegt :

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

2.4. Bereitstellung in einem Servlet- Container

Nachdem wir die grundlegenden Komponenten einer einfachen Webanwendung erstellt haben, können wir sie in einen Servlet- Container packen und bereitstellen . Das Verhalten jeder Komponente kann leicht überprüft werden, indem die gepackte War-Datei in Jetty , Tomcat oder beliebigen Servlet- Containern bereitgestellt wird , die Servlet 3.0 unterstützen.

3. Verwenden von @ServletComponentScan im Spring Boot

Sie fragen sich vielleicht , warum wir @ServletComponentScan benötigen , da wir diese Anmerkungen in den meisten Servlet- Containern ohne Konfiguration verwenden können . Das Problem liegt in eingebetteten Servlet- Containern.

Aufgrund der Tatsache, dass eingebettete Container die Annotationen @WebServlet , @WebFilter und @WebListener nicht unterstützen , hat Spring Boot, das sich stark auf eingebettete Container stützt, diese neue Annotation @ServletComponentScan eingeführt , um einige abhängige Jars zu unterstützen, die diese 3 Annotationen verwenden.

Die ausführliche Diskussion finden Sie in dieser Ausgabe auf Github.

3.1. Maven-Abhängigkeiten

Um @ServletComponentScan verwenden zu können , benötigen wir Spring Boot mit Version 1.3.0 oder höher. Fügen wir dem Pom die neueste Version von Spring-Boot-Starter-Parent und Spring-Boot-Starter-Web hinzu :

 org.springframework.boot spring-boot-starter-parent 1.5.1.RELEASE   
  org.springframework.boot spring-boot-starter-web 1.5.1.RELEASE  

3.2. Verwenden von @ServletComponentScan

Die Spring Boot App ist ziemlich einfach. Wir fügen @ServletComponentScan hinzu , um das Scannen nach @WebFilter , @WebListener und @WebServlet zu ermöglichen:

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

Ohne Änderung an der vorherigen Webanwendung funktioniert es einfach:

@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. Geben Sie die zu scannenden Pakete an

Standardmäßig scannt @ServletComponentScan aus dem Paket der mit Anmerkungen versehenen Klasse. Um anzugeben, welche Pakete gescannt werden sollen, können wir die folgenden Attribute verwenden:

  • Wert
  • basePackages
  • basePackageClasses

Der Standardwert Attribut ist ein Alias für basePackages .

Angenommen , unsere SpringBootAnnotatedApp befindet sich unter dem Paket com.baeldung.annotation , und wir möchten Klassen in dem Paket com.baeldung.annotation.components scannen, die in der obigen Webanwendung erstellt wurden. Die folgenden Konfigurationen sind äquivalent:

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

4. Unter der Haube

Die Annotation @ServletComponentScan wird von ServletComponentRegisteringPostProcessor verarbeitet . Nach dem Scannen der angegebenen Pakete nach @ WebFilter- , @ WebListener- und @ WebServlet- Annotationen verarbeitet eine Liste der ServletComponentHandler ihre Annotationsattribute und registriert gescannte Beans:

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); } } }

Wie im offiziellen Javadoc erwähnt, funktioniert die Annotation @ServletComponentScan nur in eingebetteten Servlet- Containern , was standardmäßig mit Spring Boot geliefert wird.

5. Schlussfolgerung

In diesem Artikel haben wir @ServletComponentScan vorgestellt und erläutert, wie es zur Unterstützung von Anwendungen verwendet werden kann, die von den folgenden Anmerkungen abhängen: @WebServlet , @WebFilter , @WebListener .

Die Implementierung der Beispiele und des Codes finden Sie im GitHub-Projekt.