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.