Anotasi @ServletComponentScan di Spring Boot

1. Gambaran keseluruhan

Dalam artikel ini, kita akan membaca anotasi @ServletComponentScan baru di Spring Boot.

Tujuannya adalah untuk menyokong anotasi Servlet 3.0 berikut :

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

@WebServlet , @WebFilter dan @WebListener beranotasi kelas boleh secara automatik berdaftar dengan terbenam Servlet bekas tepi menganotasi @ServletComponentScan pada @Configuration kelas dan menyatakan pakej.

Kami telah memperkenalkan penggunaan asas @WebServlet dalam Pengenalan kepada Java Servlets dan @WebFilter dalam Pengenalan kepada Memintas Pilih corak di Jawa. Untuk @WebListener , anda boleh melihat artikel ini yang menunjukkan kes penggunaan biasa pendengar web.

2. Servlet , Penapis , dan Pendengar

Sebelum terjun ke @ServletComponentScan , mari kita lihat bagaimana penjelasan: @WebServlet , @WebFilter dan @WebListener digunakan sebelum @ServletComponentScan datang ke dalam bermain.

2.1. @WebServlet

Sekarang pertama kita akan menentukan Servlet yang melayani permintaan GET dan menjawab "hello" :

@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

Kemudian penapis yang menyaring permintaan untuk menargetkan "/ halo" , dan menyiapkan "penyaringan" ke output:

@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

Akhirnya, pendengar yang menetapkan atribut khusus di ServletContext :

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

2.4. Terapkan ke Servlet Container

Setelah kita membuat komponen asas aplikasi web yang mudah, kita dapat mengemas dan menyebarkannya ke dalam wadah Servlet . Tingkah laku setiap komponen dapat disahkan dengan mudah dengan menyebarkan fail perang yang dikemas ke Jeti , Tomcat atau mana-mana kontena Servlet yang menyokong Servlet 3.0.

3. Menggunakan @ServletComponentScan dalam Spring Boot

Anda mungkin tertanya-tanya kerana kami dapat menggunakan anotasi tersebut di kebanyakan wadah Servlet tanpa sebarang konfigurasi, mengapa kita memerlukan @ServletComponentScan ? Masalahnya terletak pada bekas Servlet tertanam .

Kerana kenyataan bahawa bekas tertanam tidak menyokong @WebServlet , @WebFilter dan @WebListener penjelasan, Spring Boot, bergantung kebanyakannya pada bekas terbenam, diperkenalkan anotasi baru ini @ServletComponentScan untuk menyokong beberapa balang bergantung yang menggunakan 3 penjelasan.

Perbincangan terperinci boleh didapati dalam isu ini di Github.

3.1. Ketergantungan Maven

Untuk menggunakan @ServletComponentScan , kami memerlukan Spring Boot dengan versi 1.3.0 atau lebih tinggi. Mari tambahkan versi terkini spring-boot-starter-parent dan spring-boot-starter-web ke 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. Menggunakan @ServletComponentScan

Aplikasi Spring Boot cukup mudah. Kami menambah @ServletComponentScan untuk membolehkan pengimbasan untuk @WebFilter , @WebListener dan @WebServlet :

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

Tanpa perubahan pada aplikasi web sebelumnya, ia hanya berfungsi:

@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. Tentukan Pakej untuk Imbas

Secara lalai, @ServletComponentScan akan mengimbas dari pakej kelas yang diberi anotasi. Untuk menentukan pakej mana yang hendak diimbas, kita dapat menggunakan atributnya:

  • nilai
  • asasPaket
  • basePackageClasses

Atribut nilai lalai adalah alias untuk basePackages .

Kata kami SpringBootAnnotatedApp adalah di bawah pakej com.baeldung.annotation , dan kami mahu ke kelas imbasan dalam pakej com.baeldung.annotation.components dicipta dalam aplikasi web atas, konfigurasi berikut adalah setara:

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

4. Di bawah Tudung

The @ServletComponentScan anotasi diproses oleh ServletComponentRegisteringPostProcessor . Selepas imbasan dinyatakan pakej untuk @WebFilter , @WebListener dan @WebServlet penjelasan, senarai ServletComponentHandlers akan memproses sifat anotasi mereka, dan mendaftar kacang diimbas:

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

Seperti yang dinyatakan dalam Javadoc rasmi, anotasi @ServletComponentScan hanya berfungsi dalam bekas Servlet tertanam , itulah yang disertakan dengan Spring Boot secara lalai.

5. Kesimpulan

Dalam artikel ini, kami memperkenalkan @ServletComponentScan dan bagaimana ia boleh digunakan untuk menyokong aplikasi yang bergantung kepada mana-mana anotasi: @WebServlet , @WebFilter , @WebListener .

Pelaksanaan contoh dan kod boleh didapati dalam projek GitHub.