javascript
Spring中对于WebApplicationInitializer的理解
文章目錄
- 1、前言
- 2、WebApplicationInitializer的定義
- 3、實現原理
- 4、利用SPI我們能做什么?
- 4.1、定義一個`MyWebAppInitializer`
- 4.2、定義一個`MySpringServletContainerInitializer`
- 4.3、寫一個`MyWebAppInitializer`的實現類
- 4.4、添加配置文件`javax.servlet.ServletContainerInitializerr`
- 4.5、啟動項目測試
1、前言
在《SpringMVC學習(五)——零配置實現SpringMVC》這篇文章中我們沒有使用Spring的配置實現了一個正常的SpringMVC的功能,里面核心的一個點就是使用了WebApplicationInitializer,那這篇文章就詳細說明一下這個接口的作用。
2、WebApplicationInitializer的定義
從起初的Spring配置文件,到后來的Spring支持注解到后來的SpringBoot,Spring框架在一步步的使用注解的方式來去除Spring的配置的發展過程。WebApplicationInitializer就是取代web.xml配置的一個接口。
public interface WebApplicationInitializer {void onStartup(ServletContext var1) throws ServletException; }通過覆蓋接口提供的onStartup方法我們可以往Servlet容器里面添加我們需要的servlet、listener等,并且在Servlet容器啟動的過程中就會加載這個接口的實現類,從而起到和web.xml相同的中作用,從而可以替代以前在web.xml中所做的配置。
3、實現原理
我們首先可以從Spring源碼中找到SpringServletContainerInitializer實現類。
@HandlesTypes({WebApplicationInitializer.class}) public class SpringServletContainerInitializer implements ServletContainerInitializer {public SpringServletContainerInitializer() {}public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {LinkedList initializers = new LinkedList();Iterator var4;if(webAppInitializerClasses != null) {var4 = webAppInitializerClasses.iterator();while(var4.hasNext()) {Class initializer = (Class)var4.next();if(!initializer.isInterface() && !Modifier.isAbstract(initializer.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(initializer)) {try {initializers.add((WebApplicationInitializer)initializer.newInstance());} catch (Throwable var7) {throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);}}}}if(initializers.isEmpty()) {servletContext.log("No Spring WebApplicationInitializer types detected on classpath");} else {servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");AnnotationAwareOrderComparator.sort(initializers);var4 = initializers.iterator();while(var4.hasNext()) {WebApplicationInitializer initializer1 = (WebApplicationInitializer)var4.next();initializer1.onStartup(servletContext);}}} }這個類上面有@HandlesTypes({WebApplicationInitializer.class})這個注解,這個注解的作用是將其value中配置的一些類放入到ServletContainerInitializer。
initializers.add((WebApplicationInitializer)initializer.newInstance());最后通過循環去執行WebApplicationInitializer中的onStartup方法來實現里面的具體的具體的邏輯。
while(var4.hasNext()) {WebApplicationInitializer initializer1 = (WebApplicationInitializer)var4.next();initializer1.onStartup(servletContext); }那問題來了,Tomcat容器怎么知道先執行這個SpringServletContainerInitializer類?
這里涉及一個知識點SPI機制,SPI全稱為 Service Provider Interface,是一種服務發現機制。SPI機制是將接口實現類的全限定名配置在文件中,并由服務加載器讀取配置文件,加載實現類。這樣可以在運行時,動態為接口替換實現類。正因此特性,我們可以很容易的通過 SPI機制為我們的程序提供拓展功能。
Tomcat啟動過程中查找所有的ServletContainerInitializer實現類然后添加到StandardContext的initializers集合中,然后執行里面的onStartup方法。
Spring中SPI就是通過SpringServletContainerInitializer類來實現的
關于Web應用的啟動過程在《一個基于注解配置的Web項目的啟動流程分析》這篇文章寫的很好。
4、利用SPI我們能做什么?
可以加一些自己的啟動配置信息,把自己的Servlet打成jar包放到Tomcat服務器或者其他工程中執行。我們可以實現一個自己的SPI接口。
4.1、定義一個MyWebAppInitializer
public interface MyWebAppInitializer {void loadOnStart(ServletContext var1) throws ServletException; }4.2、定義一個MySpringServletContainerInitializer
4.3、寫一個MyWebAppInitializer的實現類
public class MyWebApplicationInitializerTest implements MyWebAppInitializer{@Overridepublic void loadOnStart(ServletContext servletContext){System.out.println("啟動執行MyWebApplicationInitializerTest的loadOnStart方法");//注冊一個為名字call的servletServletRegistration.Dynamic servletReg = servletContext.addServlet("call", CallServlet.class);servletReg.setLoadOnStartup(1);servletReg.addMapping("/call");} }其中里面的CallServlet.java如下
public class CallServlet extends HttpServlet {private static final long serialVersionUID = 3684613967452881093L;@Overridepublic void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String name = req.getParameter("name");resp.getWriter().write(name + ", if you like me, please call me!");} }4.4、添加配置文件javax.servlet.ServletContainerInitializerr
添加位置為:src -> main -> resources-> META-INF-> services ->javax.servlet.ServletContainerInitializerr
內容:com.leo.spi.MySpringServletContainerInitializer
4.5、啟動項目測試
啟動日志:
啟動執行MyWebApplicationInitializerTest的loadOnStart方法瀏覽器測試:http://localhost:8080/springmvc/call?name=leo825
上面也提到了,可以把這個SPI的方式打成jar包在其他項目或者直接在Tomcat容器這種運行。
本文的相關源碼請參考:chapter-5-springmvc-zero-configuration
spi代碼包路徑:com.leo.spi
https://gitee.com/leo825/spring-framework-learning-example.git
總結
以上是生活随笔為你收集整理的Spring中对于WebApplicationInitializer的理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringMVC学习(五)——零配置实
- 下一篇: SpringMVC学习(六)——Spri