如今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