Servlet 3.0 规范(二)注解驱动和异步请求
在 Servlet 3.0 时支持注解启动,不再需要 web.xml 配制文件。
一、Servlet 3.0 组件
Servlet 容器的组件大致可以分为以下几类:
Servlet 3.0 组件
├── 组件申明注解
| ├── @javax.servlet.annotation.WebServlet
| ├── @javax.servlet.annotation.WebFilter
| ├── @javax.servlet.annotation.WebListener
| ├── @javax.servlet.annotation.ServletSecurity
| ├── @javax.servlet.annotation.HttpMethodConstraint
| └── @javax.servlet.annotation.HttpConstraint
|
├── 配置申明
| └── @javax.servlet.annotation.WebInitParam
|
├── 上下文
| └── @javax.servlet.AsyncContext
├── 事件
| └── @javax.servlet.AsyncEvent
├── 监听器
| └── @javax.servlet.AsyncListener
|
├── Servlet 组件注册
| ├── javax.servlet.ServletContext#addServlet()
| └── javax.servlet.ServletRegistration
|
├── Filter 组件注册
| ├── javax.servlet.ServletContext#addFilter()
| └── javax.servlet.FilterRegistration
|
├── 监听器注册
| ├── javax.servlet.ServletContext#addListener()
| └── javax.servlet.AsyncListener
|
└── 自动装配
├── javax.servlet.ServletContainerInitializer
└── @javax.servlet.annotation.HandlesTypes
二、注解驱动
1.1 Servlet 3.0 注解
Servlet 3.0 常用注解: @WebServlet @WebFilter @WebInitParam @WebListener
@WebServlet("/hello")
public class HelloServert extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.getWriter().write("hello");
}
}
Tomcat 7.x 以上的版本启动,访问 localhost:8080/hello。Tomcat 对 Servlet 的支持如下:
Tomcat 6.x 实现 Servert 2.5
Tomcat 7.x 实现 Servert 3.0
Tomcat 8.x 实现 Servert 3.1
Tomcat 9.x 实现 Servert 4.0
1.2 ServletContainerInitializer
-
Servlet 容器启动会扫描当前应用的每一个 jar 包 ServletContainerInitializer 的实现。
-
通过每个 jar 包下的 META-INFO/services/javax.servlet.ServletContainerInitializer 文件:
com.github.binarylei.MyServletContainerInitializer
@HandlesTypes(HelloServert.class)
public class MyServletContainerInitializer implements ServletContainerInitializer {
/**
* @param c @HandlesTypes 指定,HelloServert 子类
* @param ServletContext 注册三大组件(Servlet Filter Listener)
*/
@Override
public void onStartup(Set<Class<?>> set, ServletContext ctx)
throws ServletException {
// 1. 处理感兴趣的类
System.out.println(set);
// 2.1. 注册 Servert
ServletRegistration.Dynamic servlet = ctx.addServlet("myServlet", HelloServert.class);
servlet.addMapping("/*");
// 2.2. 注册 Listener
ctx.addListener(MyServletContextListener.class);
// 2.3. 注册 Filter
FilterRegistration.Dynamic filter = ctx.addFilter("myFileter", MyFilter.class);
filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST),
true, "/*");
}
}
在 Servlet 3.0 时支持注解启动,其中 ServletContainerInitializer 和 HandlesTypes 都是 Servlet 3.0 的规范。
ServletContainerInitializer
只有一个方法 onStartupHandlesTypes
感兴趣的类,启动时会通过 onStartup 传递给 clazzs 参数。HandlesTypes 会找到 HelloServert 所有的子类(不包括 HelloServert 自己)
三、异步请求
@WebServlet(value = "/async", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 1. 支持异步处理 asyncSupported = true
// 2. 开启异步处理模式
AsyncContext asyncContext = req.startAsync();
// 3. 子线程处理响应
asyncContext.start(() -> {
process();
// 4. 处理结束
asyncContext.complete();
PrintWriter writer = asyncContext.getResponse().getWriter();
writer.write("async");
});
}
private void process() {
TimeUnit.SECONDS.sleep(5);
}
}
每天用心记录一点点。内容也许不重要,但习惯很重要!