首页 > 技术文章 > spring学习(十三)--自己实现SpringServletContainerInitializer

gllegolas 2019-10-29 17:23 原文

上文中,我们讲解了如何通过实现WebApplicationInitializer接口来进行spring配置,讲解了SpringServletContainerInitializer实现的机制。

本文我们模仿SpringServletContainerInitializer自己编写一个例子。

* 本例子是编写一个类MyServletContainerInitializer,实现了ServletContainerInitializer接口的onStartup()方法。
* 在MyServletContainerInitializer的onStartup()方法中找到所有的MyWebAppInitializer接口的实现类
* 然后调用MyWebAppInitializer接口实现类的loadOnStart()方法
* 这样,其他类只要实现了MyWebAppInitializer接口实现类的loadOnStart()方法,都会随着web容器启动被依次调用

* 这样做的话,后续我们可以把自己的工程打包成jar,让其它工程引用,只要新的类实现MyWebAppInitializer接口的loadOnStart()方法,都会在web容器启动的时候被调用。

下图为程序结构,一共需要编写5个文件:

 

 

 

1、定义一个servlet,供测试

package servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 测试servlet,在MyWebAppInitializerImpl的loadOnStart方法中被加载到servletContext上下文
 * @author qiaozhong
 *
 */
public class LittleBallServlet extends HttpServlet{

    private static final long serialVersionUID = 3684613967452881093L;

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
        {
            resp.getWriter().write("Hello,I am a little ball!");
        } 
}

 

2、定义接口MyWebAppInitializer,声明方法loadOnStart()

package interfaces;

import javax.servlet.ServletContext;

/**
 * 定义自己的初始化接口
 * @author qiaozhong
 *
 */
public interface MyWebAppInitializer {

    /**
     * 接口中方法,在MyServletContainerInitializer中会被调用
     * @param servletContext
     */
    public void loadOnStart(ServletContext servletContext);
}

 

3、编写MyWebAppInitializer接口的实现类,实现loadOnStart()方法 

package serviceImpl;

import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
import servlet.LittleBallServlet;
import interfaces.MyWebAppInitializer;

/**
 * MyWebAppInitializer的实现类 
 * @author qiaozhong
 *
 */
public class MyWebAppInitializerImpl implements MyWebAppInitializer{

    /**
     * 实现了MyWebAppInitializer接口中的方法loadOnStart
     * (non-Javadoc)
     * @see interfaces.MyWebAppInitializer#loadOnStart(javax.servlet.ServletContext)
     */
    public void loadOnStart(ServletContext servletContext){
        System.out.println("启动执行MyWebAppInitializerImpl loadOnStart()");
        ServletRegistration.Dynamic servletReg = servletContext.addServlet("LittleBallServlet", LittleBallServlet.class);
        servletReg.setLoadOnStartup(1);
        servletReg.addMapping("/LittleBall");
    }
}

4、编写MyServletContainerInitializer类实现javax.servlet.ServletContainerInitializer接口的onStartup方法,在该方法中,通过@HandlesTypes(MyWebAppInitializer.class)引入MyWebAppInitializer接口,扫描MyWebAppInitializer接口的所有实现类,调用其中的loadOnStart()方法。

package initializerConfig;

import interfaces.MyWebAppInitializer;
import java.lang.reflect.Modifier;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;

//引入接口类MyWebAppInitializer
@HandlesTypes(MyWebAppInitializer.class)

/**
 * 定义自己的初始化类,实现javax的ServletContainerInitializer接口,实现onStartup()方法
 * web容器初始化时候,会通过SPI机制,自动扫描ServletContainerInitializer接口所有的实现类
 * 调用ServletContainerInitializer实现类的onStartup()方法
 * @author qiaozhong
 * 
 * 本例子是编写一个类MyServletContainerInitializer,实现了ServletContainerInitializer接口的onStartup()方法。
 * 在MyServletContainerInitializer的onStartup()方法中找到所有的MyWebAppInitializer接口的实现类
 * 然后调用MyWebAppInitializer接口实现类的loadOnStart()方法
 * 这样,其他类只要实现了MyWebAppInitializer接口实现类的loadOnStart()方法,都会随着web容器启动被依次调用
 */
public class MyServletContainerInitializer implements ServletContainerInitializer{

    @Override
    public void onStartup(Set<Class<?>> set, ServletContext servletcontext)
            throws ServletException {
        if (set != null) {
            for (Class<?> waiClass : set) {
                // Be defensive: Some servlet containers provide us with invalid classes,
                // no matter what @HandlesTypes says...
                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);
                    }
                }
            }
        }
    }
}

 

5、在src/main/resources下创建文件夹META-INF/services,创建文件名为:javax.servlet.ServletContainerInitializer

该文件内容为:initializerConfig.MyServletContainerInitializer

 

测试

1、通过tomcat启动工程,会打印MyWebAppInitializer类中loadOnStart方法的日志:

 

2、访问:http://localhost:8088/mySpringDemo/LittleBall

 

推荐阅读