Die Annotation @ServletComponentScan im Spring Boot
1. Überblick
In diesem Artikel werden wir die neue Annotation von@ServletComponentScaninSpring Boot. durchgehen
Ziel ist es, die folgenden Anmerkungen inServlet 3.0zu unterstützen:
-
javax.servlet.annotation.WebFilter
-
javax.servlet.annotation.WebListener
-
javax.servlet.annotation.WebServlet
Die mit Anmerkungen versehenen Klassen@WebServlet,@WebFilter und@WebListenerkönnen automatisch in einem eingebettetenServlet-Container registriert werden, indem@ServletComponentScan in einer@Configuration-Klasse mit Anmerkungen versehen und angegeben werden die Pakete.
Wir haben die grundlegende Verwendung von@WebServlet inIntroduction to Java Servlets und@WebFilter inIntroduction to Intercepting Filter Pattern in Java eingeführt. Für@WebListener können Sie einen Blick aufthis article werfen, was einen typischen Anwendungsfall von Weblistenern zeigt.
2. Servlets,Filters undListeners
Bevor wir in@ServletComponentScan eintauchen, schauen wir uns an, wie die Anmerkungen:@WebServlet,@WebFilter und@WebListener verwendet wurden, bevor@ServletComponentScan ins Spiel kamen.
2.1. @WebServlet
Jetzt definieren wir zuerst einServlet, dasGET Anforderungen bedient und“hello” beantwortet:
@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 filtert, um“/hello” anzuvisieren, und“filtering “ der Ausgabe 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 inServletContext festlegt:
@WebListener
public class AttrListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
servletContextEvent
.getServletContext()
.setAttribute("servlet-context-attr", "test");
}
//...
}
2.4. Bereitstellung in einemServlet-Container
Nachdem wir die grundlegenden Komponenten einer einfachen Webanwendung erstellt haben, können wir sie in einenServlet-Container packen und bereitstellen. Das Verhalten jeder Komponente kann leicht überprüft werden, indem die gepackte War-Datei inJetty,Tomcat oder beliebigenServlet-Containern bereitgestellt wird, dieServlet 3.0 unterstützen.
3. Verwenden von@ServletComponentScan inSpring Boot
Sie fragen sich vielleicht, warum wir@ServletComponentScan benötigen, da wir diese Annotationen in den meistenServlet-Containern ohne Konfiguration verwenden können. Das Problem liegt in eingebettetenServlet-Containern.
Aufgrund der Tatsache, dass eingebettete Container die Annotationen@WebServlet,@WebFilter und@WebListener nicht unterstützen, habenSpring Boot,, die sich stark auf eingebettete Container stützen, diese neue Annotation@ServletComponentScan eingeführt unterstützen einige abhängige Gläser, die diese 3 Anmerkungen verwenden.
Die ausführliche Diskussion findet sich inthis issue on Github.
3.1. Maven-Abhängigkeiten
Um@ServletComponentScan verwenden zu können, benötigen wirSpring Boot mit Version 1.3.0 oder höher. Fügen wir die neueste Version vonspring-boot-starter-parent undspring-boot-starter-web zupom 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
DieSpring 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 die vorherige Webanwendung zu ändern, 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 die folgenden Attribute verwendet werden:
-
Wert
-
basePackages
-
basePackageClasses
Das Standardattributvalue ist ein Alias fürbasePackages.
Angenommen, unserSpringBootAnnotatedApp befindet sich unter Paketcom.example.annotation, und wir möchten Klassen in Paketcom.example.annotation.components scannen, die in der obigen Webanwendung erstellt wurden. Die folgenden Konfigurationen sind äquivalent:
@ServletComponentScan
@ServletComponentScan("com.example.annotation.components")
@ServletComponentScan(basePackages = "com.example.annotation.components")
@ServletComponentScan(
basePackageClasses =
{AttrListener.class, HelloFilter.class, HelloServlet.class})
4. Unter der Haube
Die Annotation@ServletComponentScan wird vonServletComponentRegisteringPostProcessor verarbeitet. Nach dem Scannen bestimmter Pakete nach@WebFilter,@WebListener und@WebServlet Annotationen verarbeitet eine Liste vonServletComponentHandlers 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 inofficial Javadoc,@ServletComponentScan annotation only works in embedded Servlet containers angegeben, was standardmäßig mitSpring Boot geliefert wird.
5. Fazit
In diesem Artikel haben wir@ServletComponentScan vorgestellt und wie es verwendet werden kann, um Anwendungen zu unterstützen, die von einer der Anmerkungen abhängen:@WebServlet,@WebFilter,@WebListener.
Die Implementierung der Beispiele und des Codes finden Sie inin the GitHub project.