下面测试使用Jetty的continuation机制,首先自定义一个服务,分别添加blockservlet和nonblockservlet。开启5个线程的线程池提供server服务。(jetty 8.1.8版本)
package test; import org.eclipse.jetty.server.*; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.thread.QueuedThreadPool; public class PJetty{ public static void main(String[] args) throws Exception { //设置connectors SelectChannelConnector connector1 = new SelectChannelConnector(); connector1.setPort(1987); connector1.setThreadPool(new QueuedThreadPool(5)); Server server = new Server(); server.setConnectors(new Connector[]{connector1}); //使用servlet处理请求 ServletContextHandler context = new ServletContextHandler(); context.setContextPath("/"); context.addServlet(new ServletHolder(new BlockingServlet()), "/block"); context.addServlet(new ServletHolder(new NonBlockingServlet()), "/nonblock"); server.setHandler(context); server.start(); server.join(); } }
先实现一个阻塞的servlet服务BlockingServlet.java如下
package test; import java.text.SimpleDateFormat; import java.util.Date; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class BlockingServlet extends HttpServlet { /** * generated serialize number */ private static final long serialVersionUID = -3402527424876194224L; SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");//可以方便地修改日期格式 public void service(HttpServletRequest req, HttpServletResponse res) throws java.io.IOException { String start = dateFormat.format( new Date() ); String sleeptime = req.getParameter("st"); res.setContentType("text/plain"); res.getWriter().println("Request: "+sleeptime+"\tstart:\t" + start); res.getWriter().flush(); try { if(sleeptime != null){ Thread.sleep(Integer.parseInt(sleeptime)*1000); } } catch (Exception e) {} String end = dateFormat.format( new Date() ); res.getWriter().println("Request: "+sleeptime+"\tend:\t" + end); } }
然后实现一个NonBlockingServlet.java如下,continuation采用suspend/resume模式
package test; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.continuation.Continuation; import org.eclipse.jetty.continuation.ContinuationSupport; public class NonBlockingServlet extends HttpServlet { /** * generated serialize number */ private static final long serialVersionUID = 3313258432391586994L; SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");//可以方便地修改日期格式 MyAsyncHandler myAsyncHandler ; public void init() throws ServletException { myAsyncHandler = new MyAsyncHandler() { public void register(final MyHandler myHandler) { try { Thread.sleep(10000); String end = dateFormat.format( new Date() ); myHandler.onMyEvent(end); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { String start = dateFormat.format( new Date() ); String reqId = request.getParameter("st"); // 如果我们需要异步方式得到一个result,并放入request中 Object results = request.getAttribute("results"); if (results==null) // 如果异步处理尚未返回结果 { final Continuation continuation = ContinuationSupport.getContinuation(request); if(continuation.isInitial()){ continuation.setTimeout(8000); response.setContentType("text/plain"); response.getWriter().println("Request: "+reqId+"\tstart:\t"+start); response.getWriter().flush(); } // 判断是否超时 if (continuation.isExpired()) { // 返回超时Response response.getWriter().println("timeout"); response.getWriter().flush(); return; } // 挂起HTTP连接 continuation.suspend(); // 注册一个异步事件处理器 myAsyncHandler.register(new MyHandler() { public void onMyEvent(Object result) { continuation.setAttribute("results", result); continuation.resume(); } }); return; // or continuation.undispatch(); } // 连接恢复后返回结果 response.getWriter().println("Request: "+reqId+"\tend:\t" + results); response.getWriter().flush(); } private interface MyAsyncHandler{ public void register(MyHandler myHandler); } private interface MyHandler{ public void onMyEvent(Object result); } }
一旦continuation被挂起,需要注册一系列回调函数,请求将被挂起一直到continuation.resume()或continuation.complete()被调用,如果都没有被调用,则超时。
运行服务,测试结果如下:
root $ for i in `seq 1 10`; do lynx -dump http://192.168.201.167:1987/block?st=$i & done Request: 1 start: 2012/12/19 10:41:59 Request: 1 end: 2012/12/19 10:42:00 Request: 4 start: 2012/12/19 10:41:59 Request: 4 end: 2012/12/19 10:42:03 Request: 9 start: 2012/12/19 10:41:59 Request: 9 end: 2012/12/19 10:42:08 Request: 2 start: 2012/12/19 10:42:08 Request: 10 start: 2012/12/19 10:42:00 Request: 2 end: 2012/12/19 10:42:10 Request: 10 end: 2012/12/19 10:42:10 Request: 8 start: 2012/12/19 10:42:03 Request: 8 end: 2012/12/19 10:42:11 Request: 3 start: 2012/12/19 10:42:10 Request: 3 end: 2012/12/19 10:42:13 Request: 5 start: 2012/12/19 10:42:11 Request: 5 end: 2012/12/19 10:42:16 Request: 7 start: 2012/12/19 10:42:10 Request: 7 end: 2012/12/19 10:42:17 Request: 6 start: 2012/12/19 10:42:13 Request: 6 end: 2012/12/19 10:42:19 root $ for i in `seq 1 10`; do lynx -dump http://192.168.201.167:1987/nonblock?st=$i & done Request: 1 start: 2012/12/19 11:43:48 Request: 1 end: 2012/12/19 11:43:49 Request: 2 start: 2012/12/19 11:43:48 Request: 2 end: 2012/12/19 11:43:50 Request: 3 start: 2012/12/19 11:43:48 Request: 3 end: 2012/12/19 11:43:51 Request: 4 start: 2012/12/19 11:43:48 Request: 4 end: 2012/12/19 11:43:52 Request: 5 start: 2012/12/19 11:43:48 Request: 5 end: 2012/12/19 11:43:53 Request: 6 start: 2012/12/19 11:43:48 Request: 6 end: 2012/12/19 11:43:54 Request: 7 start: 2012/12/19 11:43:48 Request: 7 end: 2012/12/19 11:43:55 Request: 9 start: 2012/12/19 11:43:48 Request: 10 start: 2012/12/19 11:43:48 timeout timeout Request: 8 start: 2012/12/19 11:43:56 timeout
再用ab简单测试一下,nonblock模式rps(request per second)要高好几倍的样子吧
附:当异步handler操作结束返回结果时servlet或filter用来生成响应内容,典型地做法是通过设定request的attribute来传递结果results,用来判断请求是否被挂起。而suspend/continue模式用在异步的handler产生响应时使用。
continuation的suspend/continue模式实现如下:
package test; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.continuation.Continuation; import org.eclipse.jetty.continuation.ContinuationSupport; public class NonBlockingServlet extends HttpServlet { /** * Suspend/Resume */ private static final long serialVersionUID = 3313258432391586994L; SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");//可以方便地修改日期格式 MyAsyncHandler myAsyncHandler ; public void init() throws ServletException { myAsyncHandler = new MyAsyncHandler() { public void register(final MyHandler myHandler,final String sleeptime) { new Thread(new Runnable() { public void run() { try { if(sleeptime != null){ Thread.sleep(Integer.parseInt(sleeptime)*1000); } String end = dateFormat.format( new Date() ); try { myHandler.onMyEvent(end); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } }; } protected void doGet(HttpServletRequest request, final HttpServletResponse response) throws IOException { String start = dateFormat.format( new Date() ); final String sleeptime = request.getParameter("st"); final Continuation continuation = ContinuationSupport.getContinuation(request); if(continuation.isInitial()){ response.setContentType("text/plain"); response.getWriter().println("Request: "+sleeptime+"\tstart:\t"+start); response.getWriter().flush(); } continuation.setTimeout(8000); // if this is not a timeout if (continuation.isExpired()) { // 返回超时Response response.getWriter().println("timeout"); response.getWriter().flush(); return; } // 挂起请求 continuation.suspend(response); // response may be wrapped. // register with async service. The code here will depend on the // the service used (see Jetty HttpClient for example) myAsyncHandler.register(new MyHandler() { public void onMyEvent(Object result) throws IOException { // 连接恢复后返回结果 response.getWriter().println("Request: "+sleeptime+"\tend:\t" + result); response.getWriter().flush(); continuation.complete(); } },sleeptime); } private interface MyAsyncHandler{ public void register(MyHandler myHandler,String sleeptime); } private interface MyHandler{ public void onMyEvent(Object result) throws IOException; } }
相关推荐
描述中提到含有“java源码——MySQL数据库”,这暗示了系统使用Java作为后端开发语言,而MySQL作为数据存储和管理的数据库。 在Java Web开发中,通常会使用如Spring Boot、Struts或Servlet等框架来构建服务端应用,...
【JavaWeb项目——网上淘书吧详解】 "Java Web项目-网上淘书吧.zip"是一个包含完整Java Web应用程序的压缩包,旨在实现一个在线图书交易平台,让用户能够方便地浏览、搜索和购买书籍。这个项目的核心是利用Java技术...
Web服务是一种基于网络的软件接口,它允许不同的应用程序之间进行通信和数据交换。在Java世界中,Apache ...通过学习和实践这个例子,开发者可以更好地理解和掌握Web服务的开发流程,提升在分布式系统中的编程能力。
JavaScript,通常用于前端开发,但随着Node.js的出现,JavaScript也可以在后端进行服务端编程。Node.js提供了丰富的库和框架,如Express,使得用JavaScript构建RESTful API变得简单。在这个项目中,很可能使用了...
本文将探讨一个个人学习项目——"Online-Translator",这是一个基于Java技术实现的英德与德英之间的文本翻译服务。该项目不仅展示了开发者对编程技术的理解,也体现了自主学习的重要性。 首先,让我们了解"Online-...
标题 "Web容器---Servlet" 涉及到的是Web应用程序开发中的核心概念,特别是Java Web开发中的关键元素——Servlet。Servlet是一种Java编程语言编写的服务器端程序,主要用于扩展服务器的功能,处理HTTP请求并生成响应...
10. **cxf-tools**: 提供了生成客户端和服务端代码的工具,如WSDL to Java(Wsimport)和Java to WSDL(Jaxws-ri)。 11. **其他依赖库**: 包括了如StAX, JAXB, JAXP, LOG4J, XML解析器等CXF依赖的第三方库。 在...
后端服务端可能需要配置服务器环境,如Tomcat或Jetty,部署SSM应用,并进行数据库设计,选择合适的数据模型和表结构,优化查询性能。同时,安全考虑也是必不可少的,如防止SQL注入、XSS攻击等。 总结来说,“基于...
《董事会管理器——JavaWeb应用深度解析》 在IT行业中,JavaWeb技术是构建企业级应用的重要工具,尤其在管理类系统中,如"BoardroomManager"这样的项目,其复杂性和实用性并重,展现了JavaWeb的强大功能。这个...
在这个活动中,参与者将深入学习和应用"构造学"理论,同时专注于两大主流技术框架——Spring Boot(基于Java)和React(包括React Native)。 **Java** Java是一种广泛使用的面向对象的编程语言,以其“一次编写,...
《深入解析ProjectTracker——基于Java技术的项目管理工具》 在IT行业中,项目管理是至关重要的环节,有效的项目管理能够确保项目的顺利进行,提高团队协作效率。"ProjectTracker"作为一个项目管理工具,它利用Java...
这个项目涉及到多个核心技术,包括Java后端开发、前端页面构建、数据库管理和服务器配置等,是学习和实践JavaWeb开发的绝佳案例。 **JavaWeb基础** JavaWeb是Java技术在Web应用中的应用,主要由Servlet、JSP(Java...
4. **测试友好**: 提供方便的测试工具,简化了服务端和客户端的测试。 ### `Circe` `Circe`是一个用于JSON处理的Scala库,它的设计目标是使JSON操作变得简单且富有表达力。主要特点包括: 1. **自动解码和编码**:...