`
fancy888
  • 浏览: 39808 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

使用Servlet分段输出构建BigPipe服务端

 
阅读更多

      BigPipe是一个重新设计的基础动态网页服务体系。大体思路是,分解网页成叫做Pagelets的小块,然后通过Web服务器和浏览器建立管道并管理他们在不同阶段的运行。这是类似于大多数现代微处理器的流水线执行过程:多重指令管线通过不同的处理器执行单元,以达到性能的最佳。


      使用JAVA实现BigPipe服务端的例子在网上很难寻觅,笔者经过多次尝试,在Servlet3.0和Servlet2.5规范下成功实现了BigPipe的分段输出效果。好东西不敢独享,在这里与大家分享。

      要搭建BigPipe服务端程序,首先我们必须了解BigPipe服务端的工作原理。BigPipe的最终目标是通过一次请求向浏览器输出页面框架和若干个Pagelet。浏览器在接收完页面框架后立即进行展现,然后并行的接收后面的Pagelets,从而加快页面的渲染速度。Pagelet是通过调用前端的一个JS方法向页面输出的。

      为了达到一次请求多次输出的效果,服务端程序必须采用分段输出的技术(chunked)。这里所说的chunked是指HTTP 1.1规范中定义的一个特殊的HTTP头信息,下面的一段HTTP响应头包含了chunked定义:

 

HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked

 

      通过在HTTP响应头中增加“Transfer-Encoding: chunked”标识,我们通知浏览器后面的响应内容是分段输出的,每段输出使用一个16进制的数字来声明段长度,然后紧跟一个回行换行符,后面是分段的内容体,最后使用一个0长度的分段来结束整个的chunked输出。下面是一个用Socket模拟的chunked分段输出:

 

public static void main(String[] args) throws IOException, InterruptedException {
	StringBuffer content1 = new StringBuffer("<html><body>");
	content1.append("<div id='a1' style='width:100px;height:100px;border:1px solid black'></div>");
	content1.append("<div id='a2' style='width:100px;height:100px;border:1px solid black'></div>");
	content1.append("<div id='a3' style='width:100px;height:100px;border:1px solid black'></div>");
	content1.append("<div id='a4' style='width:100px;height:100px;border:1px solid black'></div>");
	content1.append("</body></html>");
	String content2 = "<script type='text/javascript'>document.getElementById('a1').innerHTML='<h1>1</h1>'</script>";
	String content3 = "<script type='text/javascript'>document.getElementById('a2').innerHTML='<h1>2</h1>'</script>";
	String content4 = "<script type='text/javascript'>document.getElementById('a3').innerHTML='<h1>3</h1>'</script>";
	String content5 = "<script type='text/javascript'>document.getElementById('a4').innerHTML='<h1>4</h1>'</script>";

	ServerSocket ss = new ServerSocket(80);
	Socket s;
	while (true) {
		s = ss.accept();
		s.getInputStream().read();
		PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream(), "UTF-8"));
		//输出响应头
		pw.println("HTTP/1.1 200 OK");
		pw.println("Content-Type: text/html;charset=UTF-8");
		//声明分段输出
		pw.println("Transfer-Encoding: chunked");
		pw.println();
		//第一段
		//先输出段长度,注意必须是16进制,加2是因为后面有个回车换行符
		pw.println(Integer.toHexString(content1.length() + 2));
		//输出分段内容
		pw.println(content1.toString());
		//输出回车换行符结束本段输出
		pw.println();
		//立即清空输出缓冲区,通知浏览器立即处理本段内容
		pw.flush();
		//暂停1秒模拟后台处理过程
		Thread.sleep(1000);
		//第二段
		pw.println(Integer.toHexString(content2.length() + 2));
		pw.println(content2);
		pw.println();
		pw.flush();
		Thread.sleep(1000);
		//第三段
		pw.println(Integer.toHexString(content3.length() + 2));
		pw.println(content3);
		pw.println();
		pw.flush();
		Thread.sleep(1000);
		//第四段
		pw.println(Integer.toHexString(content4.length() + 2));
		pw.println(content4);
		pw.println();
		pw.flush();
		Thread.sleep(1000);
		//第五段
		pw.println(Integer.toHexString(content5.length() + 2));
		pw.println(content5);
		pw.println();
		pw.flush();
		//输出一个0长段结束整个输出
		pw.println(0);
		pw.println();
		pw.close();
		//最后别忘了关闭输出流
		s.close();
	}
 


      运行上面的代码,在浏览器中输入&quot;http://localhost&quot;应该就可以看到分段输出的效果了,注意和传统的AJAX异步请求不同,这里只有一次请求!

      通过上面使用Socket模拟的分段输出响应,我想大家已经了解了Bigpipe服务端工作的原理,下面我们通过Servlet来实现分段输出的效果。查找了好久,网上只能找到使用Servlet3.0实现分段输出的样例,得益于Servlet3.0规范新增的异步处理接口,我们可以使用很幽雅的方式来完成分段输出的效果,但我相信使用旧的Servlet规范一定也能实现分段输出的效果,事实上的确如此,我们先来看使用Servlet3.0实现的代码:

 

@WebServlet(value = { "/syncServlet" }, asyncSupported = true, loadOnStartup = 1)
public class SyncTestServlet extends HttpServlet {
	private static final long serialVersionUID = -126107068129496624L;
	private final BlockingQueue<Runnable> quere = new ArrayBlockingQueue<Runnable>(10);
	private final ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 10, TimeUnit.HOURS, quere);

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html");
		final AsyncContext sc = request.startAsync(request, response);
		final StringBuffer content = new StringBuffer("<html><body>");
		content.append("<div id='a1' style='width:100px;height:100px;border:1px solid black'></div>");
		content.append("<div id='a2' style='width:100px;height:100px;border:1px solid black'></div>");
		content.append("<div id='a3' style='width:100px;height:100px;border:1px solid black'></div>");
		content.append("<div id='a4' style='width:100px;height:100px;border:1px solid black'></div>");
		content.append("</body></html>");
		final PrintWriter pw = response.getWriter();
		pw.println(content.toString());
		pw.flush();
		executor.execute(new Job(sc, 1));
		executor.execute(new Job(sc, 2));
		executor.execute(new Job(sc, 3));
	}

}

class Job implements Runnable {
	private static int count;
	private AsyncContext syncContext;
	private int no;

	public Job(AsyncContext syncContext, int no) {
		this.syncContext = syncContext;
		this.no = no;
		count++;
	}

	public void run() {
		HttpServletResponse resp = (HttpServletResponse) syncContext.getResponse();
		try {
			Thread.sleep(no * 1000);
			PrintWriter out = resp.getWriter();
			out.println("<script type='text/javascript'>document.all.a" + no + ".innerHTML='<h1>" + no + "</h1>'</script>");
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		count--;
		if (count == 0) {
			syncContext.complete();
		}
	}
}

 

      下面是使用旧的Servlet规范实现分段输出的代码,由于旧的Servet规范没有包含异步处理功能,我们只能自己处理线程的同步和页面输出流的抢占问题。

public class BigpipeServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=UTF-8");
		final PrintWriter pw = response.getWriter();
		final StringBuffer content = new StringBuffer("<html><body>");
		content.append("<div id='a1' style='width:100px;height:100px;border:1px solid black'></div>");
		content.append("<div id='a2' style='width:100px;height:100px;border:1px solid black'></div>");
		content.append("<div id='a3' style='width:100px;height:100px;border:1px solid black'></div>");
		content.append("<div id='a4' style='width:100px;height:100px;border:1px solid black'></div>");
		content.append("</body></html>");
		pw.println(content.toString());
		pw.flush();
		final Paglet paglet1 = new Paglet(pw, 1);
		final Paglet paglet2 = new Paglet(pw, 2);
		final Paglet paglet3 = new Paglet(pw, 3);
		paglet1.start();
		paglet2.start();
		paglet3.start();
		try {
			paglet3.join();
			paglet2.join();
			paglet1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		pw.close();
	}

	class Paglet extends Thread {

		private int id;
		private PrintWriter out;

		public Paglet(PrintWriter out, int id) {
			this.out = out;
			this.id = id;
		}

		@Override
		public void run() {
			try {
				sleep(id * 1000);
				final String content = "<script>document.all.a" + id + ".innerHTML='<h1>" + id + "</h1>'</script>";
				synchronized (out) {
					out.println(content);
					out.println();
					out.flush();
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}


       原文地址:http://www.coolfancy.com/log/26.html

 

       更多精彩原创文章请关注笔者的原创博客:http://www.coolfancy.com

0
6
分享到:
评论

相关推荐

    利用Maven开发的一个基于Servlet的BigPipe简单案例.zip

    客户端向服务端发送请求后(发出一次访问请求,如请求访问个人博客首页),服务端采用并发形式获取各个pagelet的数据并渲染pagelet的页面效果.一旦某个pagelet页面渲染完成则立刻采用json形式将该pagelet页面显示结果...

    java实现bigpipe(上)

    在 Java 中,我们可以利用 Spring MVC 或者其他 Web 框架来构建 BigPipe 系统。首先,我们需要创建一个 Controller,该 Controller 将处理来自客户端的请求,并返回各个页面组件。例如: ```java @Controller @...

    bigPipe Net

    2. "BigPipe" 文件可能是一个示例或者配置文件,展示了如何配置和使用这个.NET框架,包括: - 页面配置:定义页面的Pagelet结构,以及它们的加载顺序和依赖。 - 请求和响应处理:如何将服务器返回的数据分割成...

    BigPipe技术java源代码

    **BigPipe技术详解** BigPipe是由Facebook开发的一种页面加载优化技术,它的主要目的是为了提高网页的加载速度,提升用户体验。在传统的网页加载过程中,浏览器会一次性下载整个页面的所有资源,这往往导致用户需要...

    Bigpipe命令_V45

    - **用法**:当需要了解所有 Bigpipe 命令的基本使用方法时,此命令提供了全面的帮助文档。 ##### 10. `interface` - **功能**:为单独的接口设置选项。 - **用法**:可以配置诸如 MTU、速度等参数,适用于不同类型...

    bigpipe 基于struts2标签实现

    不过,实施`BigPipe`需要对前端和后端都有深入的理解,包括JavaScript、HTTP协议、服务器端编程以及`Struts2`框架的使用。同时,为了保证最佳效果,还需要考虑资源的缓存策略、错误处理和兼容性等问题。

    Asp.net MVC2.0 BigPipe假想

    ASP.NET MVC 2.0 BigPipe 假想是一种优化Web应用性能的技术,灵感来源于Facebook的BigPipe。BigPipe的主要思想是将页面加载分为多个独立的部分,这些部分可以并行加载,从而显著提高页面渲染速度,提升用户体验。在...

    bigpipe-example, 使用koa和组件的[DEPRECATED] BigPipe.zip

    bigpipe-example, 使用koa和组件的[DEPRECATED] BigPipe BigPipe示例 使用 koa 和组件插件构建的应用程序,实现了facebook的 BigPipe 。给定 subreddit,这里应用程序执行以下操作:一个基于 horizontal-grid-...

    NET BIGPIPE vs2010

    3. **示例页面**:可能有一些演示如何使用BigPipe的ASP.NET页面,展示如何在实际项目中应用这个技术。 4. **配置文件**:可能包含Web.config文件,用于配置HTTP模块、处理程序以及其他与BigPipe相关的设置。 5. **...

    高性能页面加载技术--BigPipe设计原理及Java简单实现

    通过理解和实践BigPipe设计,开发者可以为用户构建更快、更流畅的Web应用,提高用户满意度,同时也为SEO和性能优化提供了新的思路。在Java环境中实现BigPipe,需要结合服务器端和前端技术,充分利用现代Web栈的优势...

    米聊服务端开源实践

    米聊作为一款即时通讯软件,在其服务端构建过程中采用了大量的开源技术。本文档将详细解析米聊服务端所使用的开源技术及其应用实践,包括但不限于Maven、Nexus、Nginx、Resin、Quercus、Zookeeper、Hadoop、Riak等。...

    net bigPipe

    例如,`BigPipe.sln` 可能是一个包含解决方案的文件,它可能包含了多个项目,其中一个主要项目负责实现bigPipe的逻辑。`BigPipe` 文件可能是该项目的源代码或者配置文件,其中包含了如何创建管道、管理管道以及将...

    koa-bigpipe-demo:koa-bigpipe-demo

    Koa Bigpipe演示生成基础koa工程使用koa-bigpipe作为bigpipe库默认使用pug模板引擎 jQuery + bigpipe.js $ nvm use 7Now using node v7.9.0 (npm v4.2.0)$ npm start

    bigpipe对应的tmsh命令及linux对应的tmsh命令

    bigpipe对应的tmsh命令及linux对应的tmsh命令,TMSH命令行操作bigpipe对应的tmsh命令及linux对应的tmsh命令

    C#实现仿新浪微博BigPipe

    【C#实现仿新浪微博BigPipe】是一个针对网页加载性能优化的技术实践,主要目的是通过C#编程语言模仿新浪微博的高效数据加载策略——BigPipe。BigPipe是Facebook提出的一种页面加载技术,它通过将一个网页拆分成多个...

    bigpipe-demo1:简单的 bigpipe 演示

    2. **示例页面**:一个简单的演示页面,展示了如何将一个页面分割成多个部分,并使用BigPipe进行加载。 3. **API接口**:可能有一个或多个模拟的API接口,用于返回页面片段的数据。 4. **页面片段渲染**:...

    nodejs实现bigpipe异步加载页面方案

    但需要注意的是,对于需要考虑 SEO 的网站,可能需要采取额外的措施,如使用预渲染或服务端渲染技术,以确保搜索引擎能够正确抓取和索引内容。 总的来说,Node.js 结合 BigPipe 提供了一种高效的页面加载策略,它...

    facebook bigpipe Java版本实现

    Facebook的BigPipe是一种高效网页加载技术,旨在提升用户体验,通过分块加载页面内容来显著减少网页的加载时间。它最初由Facebook开发,并已开源。在这个Java版本的实现中,我们有机会深入理解BigPipe如何在非PHP...

    BigPipe技术后端实现分享 新浪微博新版中的Bigpipe Server端的php实现 共39页.ppt

    在实现BigPipe的过程中,服务器端需要完成的任务包括组织Pagelets、管理Pagelet之间的依赖关系、获取数据以及判断输出模式。例如,服务器可能需要根据Pagelet的依赖关系来决定它们的加载顺序,确保先加载的数据能够...

    webx之bigpipe

    Webx之BigPipe技术是一种优化Web页面加载性能的方法,它借鉴了Facebook的BigPipe理念,旨在提高用户体验,尤其是在处理大量动态内容的Web应用中。Webx是一个基于Java的开源Web框架,而BigPipe则是Webx框架中的一个...

Global site tag (gtag.js) - Google Analytics