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必要条件:

  1. @WebServlet的属性 asyncSupported = true
  2. 开启异步上下文:HttpServletRequest.startAsync() 
  3. 业务逻辑内使用异步线程的方式触发回调: 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()  的执行。

加载处理过程

  1.  org.springframework.boot.web.servlet.WebServletHandler解析创建BeanDefinition时使用的是org.springframework.boot.web.servlet.ServletRegistrationBean.class。
  2. 对于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

回到顶部