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;  
	}

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值