日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring中对于WebApplicationInitializer的理解

發布時間:2025/3/19 javascript 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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
  • 實現ServletContainerInitializer接口
  • 修改@HandlesTypes為我們自己定義的MyWebAppInitializer.class
  • 實例化MyWebAppInitializer的實現類,并且調用接口的loadOnStart方法
  • @HandlesTypes(MyWebAppInitializer.class) public class MySpringServletContainerInitializer implements ServletContainerInitializer{@Overridepublic void onStartup(Set<Class<?>> set, ServletContext servletcontext)throws ServletException {if (set != null) {for (Class<?> waiClass : set) {if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&MyWebAppInitializer.class.isAssignableFrom(waiClass)) {try {//創建MyWebAppInitializer實現類的對象,并調用loadOnStart方法((MyWebAppInitializer) waiClass.newInstance()).loadOnStart(servletcontext);} catch (Throwable ex) {throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);}}}}} }
    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的理解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。