< 在此处插入图片 > JavaEE 6 Servlet 3.0 中的新特性
议题 易于开发和部署 < 在此处插入图片 > 模块化 web.xml 动态配置 异步 Servlet 2
Web Profile 用于 Web 应用程序的功能全面的中型 profile web profile 中的各种技术 Servlet 3.0 JSP 2.1 对其他语言的调试支持 EL 1.2 JSTL 1.2 JSF 2.0 EJB Lite 3.1 JTA 1.1 JPA 2.0 通用批注 Bean validation 1.0 Web Profile 完整的 JavaEE 6 3
< 在此处插入图片 > 易于开发和部署 4
简化的打包 Java EE 5 Java EE 6 foo.ear foo_web.war WEB-INF/web.xml WEB-INF/classes com.sun.fooservlet com.sun.ticktock foo.war WEB-INF/classes com.sun.fooservlet com.sun.ticktock com.sun.foobean com.sun.foohelper foo_ejb.jar com.sun.foobean com.sun.foohelper 5
Servlet 下一代 Servlet 3.0 易于开发 主要关注点 增强了 API 以便使用 SE 5 中新的语言特性 例如 : 批注 泛型 (Generics) 在上次 JavaEE 5 中漏掉的 Servlet 部署描述批注 现在 web.xml 为可选 用于保证 API 类型安全的泛型 (Generics) 不影响后向兼容性 惯例优先原则 (Convention over) 更好的默认值 例外配置 6
Servlet 2.x public class HelloServlet extends HTTPServlet { public void doget(httpservletrequest req, HttpServletResponse res) throws Exception { } } <web-app> <servlet> <servlet-name>helloservlet</servlet-name> <servlet-class>myservlet.helloservlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>helloservlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>... </web-app> 7
Servlet 3.0 示例 1 @WebServlet(name= HelloServlet, urlpatterns= /hello ) public class HelloServlet extends HttpServlet { public void doget(httpservletrequest req, HttpServletResponse res) throws Exception {... } //name= HelloServlet, urlpatterns= /hello @WebServlet( /hello ) public class HelloServlet extends HttpServlet { public void doget(httpservletrequest req, HttpServletResponse res) throws Exception {... } 无 web.xml 8
@WebServlet 用于指定 servlet 批注至少必须有 urlpattern urlpattern 属性是默认属性 即 value() 所有其他字段都有合理的默认值 例如,servlet 的名称默认为 servlet 的全称类名 类的其余内容与之前相同 必须扩展 HttpServlet 类 重写 doxxx() 来处理行为 @WebListener @WebFilter 的工作方式相同 9
Servlet 3.0 示例 3 @WebServlet( urlpatterns= /hello, loadonstartup=1, initparams={ @InitParam(name= db, value= jdbc:derby... ), @InitParam(name= dbuser, value= fred ), @InitParam(name= dbpasswd, value= fred ) } ) public class HelloServlet extends HttpServlet { public void init(servletconfig config) throws ServletException { String jdbc = config.getinitparameter( db ); } 10
使用批注 用于部署 servlet 过滤器 监听器的批注 @WebServlet 向 web.xml 中添加 servlet 项 @WebFilter 添加过滤器项 @WebListener 添加监听器项 @WebInitParam 添加参数项 @MultiPartConfig 表示 servlet 要求使用 mime/multipart 数据格式 在部署时使用 web.xml 覆盖批注值 11
Servlet 3.0 示例 2 @WebFilter(urlPatterns= /hello, dispatchertypes={ DispatcherType.FORWARD} ) public class HelloServletFilter implements Filter { public void dofilter(httpservletrequest req, HttpServletResponse res) {... } 12
Multipart 支持 Multipart 格式用于在 HTTP 流中分割传输内容 通常是表单数据 非 ASCII 数据 二进制数据等 <form action= /upload > Name: <input name= filename type= text /> File to upload: <input name= myfile type= file /> <input type= submit value= Upload > </form> POST /upload HTTP/1.0 Content-Type: multipart/form-data; boundary=----abcdefghijk ----ABCDEFGHIJK Content-Disposition: form-data; name= filename uploaded_file.txt ----ABCDEFGHIJK Content-Disposition: form-data; name= myfile ; filename= a_text_file.txt 13
Multipart 支持 Servlet 目前原生支持 multipart 数据 以前必须借助于第三方库 获得 MIME 内容的新方法 HttpServletRequest.getParts() Iterable<Part> HttpServletRequest.getPart(String name) String 类似功能 HttpServletRequest.getParameter( name ) HttpServletRequest.getPart( name ) 比前者更通用的形式 14
@MultipartConfig 批注 帮助 servlet 容器确定哪个 servlet 将处理 multipart 数据 配置容器处理数据的方式 临时文件的位置 最大文件大小 @WebServlet( /hello ) @MultipartConfig(location= /tmp ) public class HelloServlet extends HttpServlet { public void dopost(httpservletrequest req, HttpServletResponse res) { Part part = req.getpart( myfile ); InputStream is = part.getinputstream(); //Read in file... } 15
< 在此处插入图片 > 模块化 web.xml 16
最新发展 web.xml 多种非常高效的 web 框架 框架的使用需要 ( 可能是复杂的 ) 配置 如果使用多种框架则难以管理 复杂性增加 需要知道各框架之间的整合方式 例如 声明控制器 servlet 及其参数 处理请求前后所使用的过滤器 声明监听器以便管理应用程序生命周期的各点 很多这种配置在应用程序间通用 17
模块化 web.xml 允许在没有框架配置的情况下使用框架 为您的应用程序保留 web.xml 将框架配置工作放在框架这边 允许框架将它们的 web.xml 存储在自己的 JAR 中 在应用程序启动期间合并它们 web.xml 分段的概念 18
web.xml 与 web-fragment.xml web.xml <servlet> </servlet> 来自框架的 JAR web-fragment.xml <servlet> </servlet> web-fragment.xml <servlet> </servlet> 19
web-fragment.xml 用于指定整个 web.xml 的一部分 除根元素外与 web.xml 相同 <web-fragment> 位于框架的 JAR 中 META-INF/web-fragment.xml JAR 文件必须位于 WEB-INF/lib 中 20
web-fragment.xml 示例 <web-fragment> <context-param> <param-name>javax.faces.state_saving_method</param-name> <param-value>client</param-value> </context-param>... <servlet> <servlet-name>faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.facesservlet</servlet-class> <load-on-startup> 1 </load-on-startup> </servlet> <servlet-mapping> <servlet-name>faces Servlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping>... </web-fragment> 21
web-fragment.xml 示例 jsf_framework.jar META-INF/web-fragment.xml mywebapp.war WEB-INF/lib/jsf_framework.jar 22
资源共享 静态页面和 JSP 页面, 资源不再局限于应用程序的 DOCROOT 允许框架捆绑自己的资源 资源位于框架的 JAR 文件中 META-INF/resources ServletContext.getResourceAsStream() 将知道如何解析资源位置 应用程序 DOCROOT 中的资源优先于框架 JAR 文件中的资源 如果存在命名空间冲突 / 对应 DOCROOT 或 META-INF/resources 23
资源共享示例 mywebapp.war /index.jsp /WEB-INF/lib/framework.jar! /META-INF/web-fragment.xml /META-INF/resources/index.jsp /META-INF/resources/shared.jsp http://server.com/mywebapp/shared.jsp mywebapp.war!/web-inf/lib/framework.jar! /META-INF/resources/shared.jsp http://server.com/mywebapp/index.jsp mywebapp.war!/index.jsp 24
< 在此处插入图片 > 动态配置与按需加载 25
动态配置 以编程方式添加 servlet 监听器和过滤器 例如, 自动添加 Strut 的 ActionServlet 只能在下列各项中执行配置 ServletContextListener.contextInitialized() 由应用程序实现 应用程序启动时调用 ServletContainerInitializer.onStartup() 稍后详细介绍 使用返回的 Registration 对象进一步定制 例如, 映射 初始化参数 servlet 名称等 26
web.xml 配置 <servlet> <servlet-name>action</servlet-name> <servlet-class> org.apache.struts.action.actionservlet </servlet-class> <init-param> <param-name>config</param-name> <param-value> /WEB-INF/struts-config.xml </param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> 27
编程式配置 @WebListener( Auto configure Struts ) public class MyListener implements ServletContextListener { public void contextinitialized(servletcontextevent evt) { ServletContext ctx = evt.getservletcontext(); //Register the servlet ServletRegistration.Dynamic servreg = ctx.addservlet( action, org.apache.struts.action.actionservlet ); //Set init parameter servreg.setinitparameter( config, /WEB-INF/struts-config.xml ); servreg.setloadonstartup(2); //Add mappings servreg.addmapping( *.do ); //Annotate with @MultipartConfig servreg.setmultipartconfig( new MultipartConfigElement( /tmp )); } } 28
动态配置的局限 注册仅发生在应用程序启动时 之后不能更改 无法以编程方式删除 servlet 无法从 web.xml 删除项 只能在其上下文或上下文分支中安装 servlet/ 过滤器 / 监听器 例如 /myapp /myapp/invoice 无法共享全局状态 每个 分布式 应用程序一个实例 29
按需加载 按需加载库和框架 JSF web 服务 第三方框架 应用程序启动时 Web 容器找到使用的框架 调用 ServletContainerInitializer.onStartup() 来初始化框架 / 库 功能类似于 ServletContextListener.contextInitialized() ServletContextListener.contextInitialized() 由应用程序开发人员实现 ServletContainerInitializer.onStartup() 由框架开发人员实现 30
ServletContainerInitializer 框架实现 ServletContainerInitializer 应用程序启动时调用 onstartup() 负责初始化框架 如果有 例如, 注册控制器 servlet 连接到数据库等 通过 @HandlesTypes 实现批注 将 initializer 与它的批注 类或接口集相关联 例如 @HandlesTypes({Fred.class}) 在 META-INF/services/ 中注册 在运行时由 JavaEE 发现 Web 容器扫描 web 应用程序来寻找 @HandlesTypes 找到时调用 initializer 31
按需加载示例 1 @MyWebFramework public class DoSomething { 框架类 public class DoSomething extends MyWebFramework { public class DoSomethng implements MyWebFramework { 32
按需加载示例 2 myframework.jar META-INF/services/ javax.servlet.servletcontainerinitializer myframework.frameworkloader @HandlesTypes(MyWebFramework.class) public class FrameworkLoader implements ServletContainerInitializer { } public void onstartup(set<class<?>> c, ServletContext ctx) { //Load framework controller ctx.addservlet( SuperFrameworkController, myframework.controller.frameworkcontroller ); //Other processing... } 33
使用框架时解析 myframework.jar META-INF/web-fragment.xml META-INF/resources index.jsp images/logo.jpg META-INF/services/ 框架配置 框架配置 javax.servlet.servletcontainerinitializer myframework.frameworkloader 框架初始化 34
< 在此处插入图片 > 异步 Servlet 35
等待反应缓慢的资源 浏览器 Web 服务器数据库 Web 服务 被阻塞的线程 36
为什么要使用异步 Servlet? 非常适用于以下情况的 web 应用程序 长处理时间或伪长处理时间 等待资源释放 如数据库连接 等待事件发生 如聊天消息 等待缓慢服务的响应 如 web 服务 释放当前请求处理以便处理其他请求 为 web 容器提供了更好的可伸缩性 浏览器将仍然显示为等待 用户体验没有改变 不要与异步 I/O 混淆 目前的 Servlet 3.0 不支持 37
异步 Servlet 浏览器 Web 服务器数据库 Web 服务 请求线程 释放后可用于处理 请他请求 38
AsyncContext 调用 HttpServletRequest.startAsync() 将 servlet 置于异步模式 流将不在从 Servlet.service() 返回时提交 返回 AsyncContext 对象 AsyncContext.start() 启动请求 将其指派给工作线程 AsyncContext.dispatch() 通知工作已经完成 将控制传递回 web 容器 39
异步 Servlet 示例 1 @WebServlet(urlPatterns= /hello, asyncsupported=true) public class HelloServlet extends HttpServlet { public void doget(httpservletrequest req, HttpServletResponse res) throws Exception { //Put the request in async mode AsyncContext asyncctx = req.startasync(); //Create an instance of handler SlowResourceHandler handler = new SlowResourceHandler(asyncCtx); } //Starts the process asyncctx.start(handler); //Request will not commit on return 40
异步 Servlet 示例 2 public class SlowResourceHandler implements Runnable { private AsyncContext asyncctx; public SlowResourceHandler(AsyncContext c) { asyncctx = c; } } public void run() { //Perform some long running task... //Dispatches to the response //Completes the request asyncctx.dispatch( displayresult.jsp ); } 41
< 在此处插入图片 > 案例研究 结账 42
购物车结账 结账操作成本高昂 耗时漫长 创建订单 处理商品 ( 例如, 特价商品 ) 信用卡验证和支付 更新客户帐户 制作交货单等 在完成所有这些独立的操作之前, 请求线程将被阻塞 可选择分流到异步 servlet 请求线程将被释放 在结账完成时处理响应 允许独立于处理线程限制请求线程 43
结账 3 种实现 44
异步 EJB EJB 3.1 引入了异步 EJB 在类或方法上使用 @Asynchronous 批注 以 void 作为返回类型, 实现即发即弃 以 Future<?> 作为返回类型, 实现稍后获取结果 EJB 的执行由容器调度 可将 EJB 打包在 WAR 文件中 简化的打包 45
CheckOutServlet @WebServlet( /checkout, asyncsupported=true) @ServletConstraint( value=@httpconstraint(transportguarantee=confidential) httpmethodconstraints={@httpmethodconstraint( value= POST, rolesallowed={ authenticate })) public class CheckOutServlet extends HttpServlet {... @EJB CheckOutBean checkoutbean; public void dopost(... request,... response) { //Perform some checking... AsyncContext ctx = request.startasync(); checkoutbean.processasync(ctx); //Request thread freed on exit } 46
CheckOutBean @Stateless public class CheckOutBean { @TransactionAttribute(REQUIRED) @Asynchronous public void processasync(asynccontext ctx) { try { //Process checkout... ctx.dispatch( /checkout-success ); } catch (Exception e) { sessioncontext.rollbackonly();... ctx.dispatch( /checkout-failed ); } } 47
< 在此处插入图片 > 总结 48
总结 2.4 之后的重大修订 编程模型与其他 EE 规范更趋一致 可插拔性与按需加载 将责任交给框架开发人员 为 Comet 样式的应用程序提供更好的支持 49
硬件和软件, 集成设计 卓越性能 50