如今JavaConfig配置方式在逐步取代xml配置方式。而WebApplicationInitializer能夠看作是Web.xml的替代,它是一個接口。經過實現WebApplicationInitializer,在其中能夠添加servlet,listener等,在加載Web項目的時候會加載這個接口實現類,從而起到web.xml相同的做用。下面就看一下這個接口的詳細內容。java
首先打開這個接口,以下:web
public interface WebApplicationInitializer { void onStartup(ServletContext var1) throws ServletException; }
只有一個方法,看不出什麼頭緒。可是,在這個包下有另一個類,SpringServletContainerInitializer。它的實現以下:spring
package org.springframework.web; import java.lang.reflect.Modifier; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.HandlesTypes; import org.springframework.core.annotation.AnnotationAwareOrderComparator; @HandlesTypes({WebApplicationInitializer.class}) public class SpringServletContainerInitializer implements ServletContainerInitializer { public SpringServletContainerInitializer() { } public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { List<WebApplicationInitializer> initializers = new LinkedList(); Iterator var4; if(webAppInitializerClasses != null) { var4 = webAppInitializerClasses.iterator(); while(var4.hasNext()) { Class<?> waiClass = (Class)var4.next(); if(!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) { try { initializers.add((WebApplicationInitializer)waiClass.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 initializer = (WebApplicationInitializer)var4.next(); initializer.onStartup(servletContext); } } } }
這個類就比較有意思了,先無論其餘的,讀一下這段代碼,能夠獲得這樣的意思。app
先判斷webAppInitializerClasses這個Set是否爲空。若是不爲空的話,找到這個set中不是接口,不是抽象類,而且是ide
WebApplicationInitializer接口實現類的類,將它們保存到list中。當這個list爲空的時候,拋出異常。不爲空的話就按照必定的順序排序,並將它們按照必定的順序實例化。調用其onStartup方法執行。到這裏,就能夠解釋WebApplicationInitializer實現類的工做過程了。可是,在web項目運行的時候,SpringServletContainerInitializer這個類又是怎樣被調用的呢。spa
它只有一個接口,ServletContainerInitializer,經過它就能夠解釋SpringServletContainerInitializer是如何被調用的。它的內容以下:.net
package javax.servlet; import java.util.Set; public interface ServletContainerInitializer { void onStartup(Set<Class<?>> var1, ServletContext var2) throws ServletException; }
首先,這個接口是javax.servlet下的。官方的解釋是這樣的:爲了支持能夠不使用web.xml。提供了ServletContainerInitializer,它能夠經過SPI機制,當啓動web容器的時候,會自動到添加的相應jar包下找到META-INF/services下以ServletContainerInitializer的全路徑名稱命名的文件,它的內容爲ServletContainerInitializer實現類的全路徑,將它們實例化。既然這樣的話,那麼SpringServletContainerInitializer做爲ServletContainerInitializer的實現類,它的jar包下也應該有相應的文件。打開查看以下:3d
哈,如今就能夠解釋清楚了。首先,SpringServletContainerInitializer做爲ServletContainerInitializer的實現類,經過SPI機制,在web容器加載的時候會自動的被調用。(這個類上還有一個註解@HandlesTypes,它的做用是將感興趣的一些類注入到ServletContainerInitializerde), 而這個類的方法又會掃描找到WebApplicationInitializer的實現類,調用它的onStartup方法,從而起到啓動web.xml相同的做用。code
而後,咱們本身經過一個實例來實現相同的功能,經過同樣的方式來訪問一個servlet。xml
一、定義接口WebParameter,它就至關於WebApplicationInitializer。內容以下:
public interface WebParameter { void loadOnstarp(ServletContext servletContext); }
能夠在這裏面添加servlet,listener等。
二、定義Servlet。
public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("TestSetvlet"); } }
三、定義MyWebParameter做爲WebParameter的實現類,將Servlet添加到上下文,並設置好映射。
public class MyWebParameter implements WebParameter { public void loadOnstarp(ServletContext servletContext) { ServletRegistration.Dynamic testSetvelt=servletContext.addServlet("test","com.test.servlet.MyServlet"); testSetvelt.setLoadOnStartup(1); testSetvelt.addMapping("/test"); } }
固然,也能夠把第2步和第3步合在一塊兒:
public class MyServlet extends HttpServlet implements WebParameter { @Override public void loadOnstarp(ServletContext servletContext) { ServletRegistration.Dynamic testSetvelt=servletContext.addServlet("test","com.test.servlet.MyServlet"); testSetvelt.setLoadOnStartup(1); testSetvelt.addMapping("/test"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("TestSetvlet"); } }
並且之後能夠將Spring的applicationContext.xml與web.xml融合在一個類中。即註解爲@Configuration,並實現WebApplicationInitializer。
四、定義好WebConfig做爲ServletContainerInitializer的實現類,它的做用是掃描找到WebParameter的實現類,並調用其方法。
@HandlesTypes({WebParameter.class}) public class WebConfig implements ServletContainerInitializer { public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException { Iterator var4; if (set!=null){ var4=set.iterator(); while(var4.hasNext()){ Class<?> clazz= (Class<?>) var4.next(); if (!clazz.isInterface()&& !Modifier.isAbstract(clazz.getModifiers())&&WebParameter.class.isAssignableFrom(clazz)){ try { ((WebParameter) clazz.newInstance()).loadOnstarp(servletContext); }catch (Exception e){ e.printStackTrace(); } } } } } }
五、根據SPI機制,定義一個META-INF/services文件夾,並在其下定義相關文件名稱,並將WebConfig的類全名稱填入其中。
六、最終結果:
本文轉自:https://blog.csdn.net/zq17865815296/article/details/79464403