`

Java学习——Jetty服务端编程

 
阅读更多

下面测试使用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_web-网上实验室预约系统.zip

    描述中提到含有“java源码——MySQL数据库”,这暗示了系统使用Java作为后端开发语言,而MySQL作为数据存储和管理的数据库。 在Java Web开发中,通常会使用如Spring Boot、Struts或Servlet等框架来构建服务端应用,...

    Java web项目-网上淘书吧.zip

    【JavaWeb项目——网上淘书吧详解】 "Java Web项目-网上淘书吧.zip"是一个包含完整Java Web应用程序的压缩包,旨在实现一个在线图书交易平台,让用户能够方便地浏览、搜索和购买书籍。这个项目的核心是利用Java技术...

    axis实现的web service例子

    Web服务是一种基于网络的软件接口,它允许不同的应用程序之间进行通信和数据交换。在Java世界中,Apache ...通过学习和实践这个例子,开发者可以更好地理解和掌握Web服务的开发流程,提升在分布式系统中的编程能力。

    meme-classifier:分类模因

    JavaScript,通常用于前端开发,但随着Node.js的出现,JavaScript也可以在后端进行服务端编程。Node.js提供了丰富的库和框架,如Express,使得用JavaScript构建RESTful API变得简单。在这个项目中,很可能使用了...

    Online-Translator:为我的德语独立学习制作的简单网络翻译服务

    本文将探讨一个个人学习项目——"Online-Translator",这是一个基于Java技术实现的英德与德英之间的文本翻译服务。该项目不仅展示了开发者对编程技术的理解,也体现了自主学习的重要性。 首先,让我们了解"Online-...

    web容器---servlet

    标题 "Web容器---Servlet" 涉及到的是Web应用程序开发中的核心概念,特别是Java Web开发中的关键元素——Servlet。Servlet是一种Java编程语言编写的服务器端程序,主要用于扩展服务器的功能,处理HTTP请求并生成响应...

    apache-cxf-2.7.6所有jar包

    10. **cxf-tools**: 提供了生成客户端和服务端代码的工具,如WSDL to Java(Wsimport)和Java to WSDL(Jaxws-ri)。 11. **其他依赖库**: 包括了如StAX, JAXB, JAXP, LOG4J, XML解析器等CXF依赖的第三方库。 在...

    基于SSM的数学辅导系统和微信小程序源码.zip

    后端服务端可能需要配置服务器环境,如Tomcat或Jetty,部署SSM应用,并进行数据库设计,选择合适的数据模型和表结构,优化查询性能。同时,安全考虑也是必不可少的,如防止SQL注入、XSS攻击等。 总结来说,“基于...

    BoardroomManager.zip

    《董事会管理器——JavaWeb应用深度解析》 在IT行业中,JavaWeb技术是构建企业级应用的重要工具,尤其在管理类系统中,如"BoardroomManager"这样的项目,其复杂性和实用性并重,展现了JavaWeb的强大功能。这个...

    fullstackweek:全日制比赛周

    在这个活动中,参与者将深入学习和应用"构造学"理论,同时专注于两大主流技术框架——Spring Boot(基于Java)和React(包括React Native)。 **Java** Java是一种广泛使用的面向对象的编程语言,以其“一次编写,...

    ProjectTracker

    《深入解析ProjectTracker——基于Java技术的项目管理工具》 在IT行业中,项目管理是至关重要的环节,有效的项目管理能够确保项目的顺利进行,提高团队协作效率。"ProjectTracker"作为一个项目管理工具,它利用Java...

    FriendBook_JavaWeb:Javaweb项目

    这个项目涉及到多个核心技术,包括Java后端开发、前端页面构建、数据库管理和服务器配置等,是学习和实践JavaWeb开发的绝佳案例。 **JavaWeb基础** JavaWeb是Java技术在Web应用中的应用,主要由Servlet、JSP(Java...

    simple-http4s-api:只是在Play Json和Circe之上使用“ http4s”和Json支持的简单API

    4. **测试友好**: 提供方便的测试工具,简化了服务端和客户端的测试。 ### `Circe` `Circe`是一个用于JSON处理的Scala库,它的设计目标是使JSON操作变得简单且富有表达力。主要特点包括: 1. **自动解码和编码**:...

Global site tag (gtag.js) - Google Analytics