这个是属于servlet3.0的规范,tomcat的一个实现
spring使用了这个实现,我们同样可以使用这个实现
WebApplicationInitializer
我们知道在springmvc项目中如果实现WebApplicationInitializer接口,然后在onStartup
方法中写的代码就会在tomcat启动时执行
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println("WebApplicationInitializer被调用了");
}
}
可是这是为什么呢?这就要看看SpringServletContainerInitializer这个类,具体的代码不再分析,在它的onStartup
方法中最后我们可以看到如下代码
这就解释了为什么所有WebApplicationInitializer的实现类的onStart
方法最后都被执行
可是这些实现类是如何被找到的呢?这里需要看看SpringServletContainerInitializer实现的接口,也正是ServletContainerInitializer帮助SpringServletContainerInitializer找到了WebApplicationInitializer的所有实现类,当然不光只靠这一个实现类,还有这个类上面的@HandlesTypes注解,显然这个接口标识了WebApplicationInitializer接口。
下面会对ServletContainerInitializer进行分析和简单介绍如何使用
ServletContainerInitializer
这里不会对ServletContainerInitializer的源码进行分析,只是分析SpringServletContainerInitializer是如何找到所有WebApplicationInitializer的实现类的。
ServletContainerInitializer是servlet3.0才出现的组件,通过实现这个接口的onStart方法,就可以在tomcat的启动时执行此方法。
当然不是这样就直接可以使用的,还需要在classpath下的META-INF文件夹下创建一个services文件夹,同时在services文件夹下创建一个文字为javax.servlet.ServletContainerInitializer
的文件,里面需要写上实现了ServletContainerInitializer接口的实现类的全名。
下面就是在springmvc源码中SpringServletContainerInitializer的全名就是添加在上面所说的位置
同时如果想要获得所有WebApplicationInitializer接口的实现类必须在SpringServletContainerInitializer类上加上一个@HandlesTypes注解,其中传入WebApplicationInitializer的class对象,这样就可以获得项目中所有实现WebApplicationInitializer接口的实现类了,在onStart方法中的第一个set集合参数中就是所有实现类的集合。
既然实现的原理是这样的,我们同样也可以使用ServletContainerInitializer接口完成tomcat启动时的执行逻辑,同时获得指定接口的所有实现类
自己实现的ServletContainerInitializer
@HandlesTypes(Test.class)
public class TestInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
for (Class<?> aClass : set) {
System.out.println(aClass);
}
}
}
需要寻找实现类的接口
public interface Test {
}
实现类
public class TestDemo implements Test {
}
注册ServletContainerInitializer的实现类
打印结果