SpringBoot内嵌Tomcat(9)@WebServlet自定义Servlet加载
需要在启动SpringBootApplication类上增加注解:org.springframework.boot.web.servlet.ServletComponentScan。其引入的org.springframework.boot.web.servlet.ServletComponentScanRegistrar.addPostProcessor方法中加载的org.springframework.boot.web.servlet.ServletComponentRegisteringPostProcessor类
通过org.springframework.boot.web.servlet.ServletComponentHandler的具体实现org.springframework.boot.web.servlet.WebServletHandler来加载javax.servlet.annotation.WebServlet的BeanDefinition。
ps:
在org.apache.catalina.startup.Tomcat.addServlet方法中使用org.apache.catalina.startup.Tomcat.ExistingStandardWrapper 包装已经存在的Servlet时会判定是否有注解javax.servlet.annotation.WebServlet。
调用入口是:org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory.prepareContext方法
撸一个
标准使用异步Servlet必要条件:
- @WebServlet的属性 asyncSupported = true
- 开启异步上下文:HttpServletRequest.startAsync()
- 业务逻辑内使用异步线程的方式触发回调: AsyncContext.complete()
@WebServlet(urlPatterns = "/async", asyncSupported = true)@Slf4j
public class AsyncServlet extends HttpServlet {
ExecutorService executorService = Executors.newSingleThreadExecutor();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
log.info("step into AsyncServlet");
// step1: 开启异步上下文
final AsyncContext ctx = req.startAsync();
ctx.getResponse().getWriter().print("async servlet1");
ctx.getResponse().getWriter().flush(); // 并不会立即输出。也是等到ctx.complete() 一并输出
// step2: 提交线程池异步执行
executorService.execute(() -> {
try {
log.info("async SocketEvent.OPEN_READ 准备执行了");
// 模拟耗时
Thread.sleep(1000L);
ctx.getResponse().getWriter().print("async servlet2");
log.info("async SocketEvent.OPEN_READ 执行了");
} catch (Exception e) {
e.printStackTrace();
}
//step3: 完成回调输出。
ctx.complete();
});
}
}
输出Response都会延时到 ctx.complete() 的执行。
加载处理过程
- org.springframework.boot.web.servlet.WebServletHandler解析创建BeanDefinition时使用的是org.springframework.boot.web.servlet.ServletRegistrationBean.class。
- 对于org.springframework.web.servlet.DispatcherServlet的包装使用的是org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean。
执行堆栈如下图:
启动Tomcat过程中执行到org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize方法体内:
首先getServletContextInitializerBeans():
在 org.springframework.boot.web.servlet.ServletContextInitializerBeans.addServletContextInitializerBean方法归集了ServletRegistrationBean
(DispatcherServlet的处理也是如此).
接着回到主方法执行ServletContextInitializer.onStartup: 将Servlet注册到ServletContext中
执行到org.springframework.boot.web.servlet.RegistrationBean.onStartup -> org.springframework.boot.web.servlet.DynamicRegistrationBean.register里:
第一步:创建org.apache.catalina.core.ApplicationServletRegistration对象
ServletRegistrationBean.addRegistration :
-> org.apache.catalina.core.ApplicationContext.addServlet: 在这里创建了StandardWrapper, 其内部asyncSupported默认是false.
第二步:设置属性
ServletRegistrationBean.configure
-> org.springframework.boot.web.servlet.DynamicRegistrationBean.configure
这里取的就是ServletRegistrationBean在实例化设置的asyncSupported属性值
-> org.apache.catalina.core.ApplicationServletRegistration.setAsyncSupported -> 最终执行到了org.apache.catalina.core.StandardWrapper.setAsyncSupported
以上是 SpringBoot内嵌Tomcat(9)@WebServlet自定义Servlet加载 的全部内容, 来源链接: utcz.com/z/516637.html