Spring中WebApplicationInitializer的理解

Posted nizuimeiabc1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring中WebApplicationInitializer的理解相关的知识,希望对你有一定的参考价值。

现在JavaConfig配置方式在逐步取代xml配置方式。而WebApplicationInitializer可以看做是Web.xml的替代,它是一个接口。通过实现WebApplicationInitializer,在其中可以添加servlet,listener等,在加载Web项目的时候会加载这个接口实现类,从而起到web.xml相同的作用。下面就看一下这个接口的详细内容。

     首先打开这个接口,如下:

public interface WebApplicationInitializer 
    void onStartup(ServletContext var1) throws ServletException;

只有一个方法,看不出什么头绪。但是,在这个包下有另外一个类,SpringServletContainerInitializer。它的实现如下:

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);
            
 
        
    

这个类就比较有意思了,先不管其他的,读一下这段代码,可以得到这样的意思。

             先判断webAppInitializerClasses这个Set是否为空。如果不为空的话,找到这个set中不是接口,不是抽象类,并且是

WebApplicationInitializer接口实现类的类,将它们保存到list中。当这个list为空的时候,抛出异常。不为空的话就按照一定的顺序排序,并将它们按照一定的顺序实例化。调用其onStartup方法执行。到这里,就可以解释WebApplicationInitializer实现类的工作过程了。但是,在web项目运行的时候,SpringServletContainerInitializer这个类又是怎样被调用的呢。

           它只有一个接口,ServletContainerInitializer,通过它就可以解释SpringServletContainerInitializer是如何被调用的。它的内容如下:

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包下也应该有相应的文件。打开查看如下:

技术图片

哈,现在就可以解释清楚了。首先,SpringServletContainerInitializer作为ServletContainerInitializer的实现类,通过SPI机制,在web容器加载的时候会自动的被调用。(这个类上还有一个注解@HandlesTypes,它的作用是将感兴趣的一些类注入到ServletContainerInitializerde), 而这个类的方法又会扫描找到WebApplicationInitializer的实现类,调用它的onStartup方法,从而起到启动web.xml相同的作用。

         然后,我们自己通过一个实例来实现相同的功能,通过一样的方式来访问一个servlet。

        

         1、定义接口WebParameter,它就相当于WebApplicationInitializer。内容如下:

public interface WebParameter 
 
    void loadOnstarp(ServletContext servletContext);

可以在这里面添加servlet,listener等。

2、定义Servlet。

public class MyServlet extends HttpServlet 
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
        resp.getWriter().write("TestSetvlet");
    

3、定义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。

4、定义好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();
                    
                
            
        
    

  5、根据SPI机制,定义一个META-INF/services文件夹,并在其下定义相关文件名称,并将WebConfig的类全名称填入其中。

技术图片

6、最终结果:

技术图片

 

 技术图片

 

本文转自:https://blog.csdn.net/zq17865815296/article/details/79464403

以上是关于Spring中WebApplicationInitializer的理解的主要内容,如果未能解决你的问题,请参考以下文章

Spring Day01 Spring 框架概述以及Spring中基于XML的IOC配置

学习笔记——Spring简介;Spring搭建步骤;Spring的特性;Spring中getBean三种方式;Spring中的标签

spring中 实体类在啥时候交给spring容器管理?

怎么把自己创建的对象加到spring容器中。让spring管理

如何在Maven中配置Spring依赖

Spring中如何在非Spring管理的Bean中获取到Spring管理的Bean并操作