上一节,我们说了Servlet3.0规范里面的一些简单注解,利用它们可以来注册Servlet、Filter及Listenser等组件。
这一讲,我们来说ServletContainerInitializer。
打开Servlet3.0标准规范文档,找到Annotations and pluggability这一章节下的8.2 Pluggability这一小节,找到之后,再找到该小节下的最后一个小节,即Shared libraries / runtimes pluggability,翻译过来,应该是共享库/运行时可插拔。

这是一个非常重要的机制,该机制在后来我们框架整合里面用到的非常多。
An instance of the ServletContainerInitializer is looked up via the jar services API by the container at container / application startup time.
在容器(即Servlet容器,比如Tomcat)/应用程序启动时,容器通过jar服务API查找ServletContainerInitializer的实例。
也就是当Servlet容器启动我们的应用时,它会扫描应用下每个jar包里面的ServeletContainerInitializer的实现类。那从哪里找呢,看文档上描述是必须把ServletContainerInitializer的实现类绑定在META-INF/services/ 目录下面名字叫javax.servlet.ServletContainerInitializer的文件里面。
其实就是在META-INF/services/javax.servlet.ServletContainerInitializer文件里面写上ServletContainerInitializer实现类的全类名。
总结一下:Servlet容器在启动应用的时候,扫描当前应用每个jar包里面的META-INF/services/javax.servlet.ServletContainerInitializer文件中指定的实现类,然后运行实现类。
参考https://blog.csdn.net/m0_51545690/article/details/123077550
搭建一个普通的java项目,之前的maven项目演示有些问题,所以需要搭建一个简单的java项目,然后把项目部署到tomcat上。
搭建完如下:

@HandlesTypes(HelloService.class)
public class MyServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
System.out.println("MyServletContainerInitializer.onStartup ...");
System.out.println("class set:" + set);
}
}
我们根据文档描述指定,tomcat容器启动会调用MyServletContainerInitializer的onStartup的方法。
该方法的两个参数是什么意思呢?
public interface HelloService {
}
public class HelloServiceImp implements HelloService{
}
在@HandlesType指定HelloService.class,就能把HelloServiceImp传递给我们。
MyServletContainerInitializer.onStartup ...
class set:[class com.study.servlet.HelloServiceImp]
即Servlet容器在启动应用的时候,会将@HandlesTypes注解里面指定的类型下面的子类,包括实现类或者子接口等,全部都给我们传递过来。只要给我们传入了某一感兴趣的类型,就可以利用反射来创建对象了啊!
以上就是基于运行时插件的ServletContainerInitializer机制。
这个机制最重要的就是要启动ServletContainerInitializer的实现类,然后就能传入我们感兴趣的类型了。
该机制有两个核心,一个是ServletContainerInitializer,一个是@HandlesTypes注解。