ServletContainerInitializer机制

发布时间:
更新时间:
🕒 阅读时间:3 min read 👀 阅读量:Loading...

1. 什么是SCI

ServletContainerInitializer 是 Jakarta EE (Servlet API) 规范预留的监听入口,当容器启动时会进行SCI的扫描,比监听器、过滤器这些更顶层。将 ServletContext进行回调,可以让我们自己拿着项目的ServletContext去做一些事情(未完成项目启动之前)。

2. 官方

Jakarta ServletContainerInitializer 官网

image-20250208140404857

image-20250208140450058

3. SCI机制

3.1 ServletContainerInitializer.java

package jakarta.servlet;
import java.util.Set;
public interface ServletContainerInitializer {
// Servlet 容器 [如:Tomcat] 启动项目时传递 此项目的 ServletContext
void onStartup(Set<Class<? > classes, ServletContext servletContext) throws ServletException;
}
  1. ServletContainerInitializer 带有特殊引擎机制可被扫描注册和编程式注册

  2. 扫描注册由 Tomcat 这样的 Servlet 容器内置支持

  3. 编程式注册 需要 Tomcat 内部API支持、而非 servlet.api

  4. 未配置 @HandlesTypes 注解时、Set<Class<? > classes 总是为空

  5. 扫描注册须声明: META-INF/services/jakarta.servlet.ServletContainerInitializer

3.2 @HandlesTypes

对于实现了SCI接口的类来说,在实现类上打上该注解,并设置接口类,在容器启动时SCI机制则将@HandlesTypes中参数的类放入Set 中。

CustomServletContainerInitializer

import jakarta.servlet.ServletContainerInitializer;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.HandlesTypes;
import java.util.Set;
@HandlesTypes(ApplicationServletContainerInitializer.class)
public class CustomServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<? > waiClasses, ServletContext servletContext) throws ServletException
{
// 此处 Set<Class<?>> 为 所有的 ApplicationServletContainerInitializer 类型 class
// 一般处理逻辑为: 遍历 waiClasses
// 1. 判断是不是接口类型
// 2. 判断是不是抽象类类型
// 3. 再次严格确认 是不是该 ApplicationServletContainerInitializer 类型
// 4. new ApplicationServletContainerInitializer 对象
// 5. 调用 其中约定的方法
// 6. ApplicationServletContainerInitializer::onStartup(servletContext)
}
}

ApplicationServletContainerInitializer

import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
public interface ApplicationServletContainerInitializer {
void onStartup(ServletContext servletContext) throws ServletException;
}

4. 示例

CustomServletContainerInitializer

package com.example.springtomcat;
import jakarta.servlet.ServletContainerInitializer;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.HandlesTypes;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.Set;
@HandlesTypes(SystemServiceInitializer.class)
public class CustomServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<? > scInitializerClasses, ServletContext ctx) throws ServletException {
for (Class<?> c : scInitializerClasses) {
if (!c.isInterface() & !Modifier.isAbstract(c.getModifiers())) {
try {
Constructor<?> constructor = c.getDeclaredConstructor();
SystemServiceInitializer initializer = (SystemServiceInitializer) constructor.newInstance();
initializer.onStartup(ctx);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
}

SystemServiceInitializer

package com.example.springtomcat;
import jakarta.servlet.ServletContext;
public interface SystemServiceInitializer {
void onStartup(ServletContext servletContext);
}

CustomServiceInitializerImpl

package com.example.springtomcat;
import jakarta.servlet.ServletContext;
public class CustomServiceInitializerImpl implements SystemServiceInitializer {
@Override
public void onStartup(ServletContext servletContext) {
System.out.println("执行初始化操作 . ");
}
}

ServletContainerInitializer机制

作者: Mindspark

本文链接: https://oxai.net.cn/posts/d6cd014f

本文采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

留言评论

2000年1月1日星期六
00:00:00