Jetty 服务器的知识

         也许你还没有听说过这个Jetty服务器,不过它确实是一种比较轻量级的Java服务器,和Tomcat一样,专门解释JavaWeb程序的服务器。因为在之前学习Java Web 的时候总是遇到Tomcat配置出错,什么WebRoot目录之类的,不知道你有没有遇到过。偶然的一个机会接触到了Jetty服务器,因为我们可以直接在Java项目中使用这个服务器,需要的就只是简单地把相关的JAR包导入即可,也可以像普通的服务器那样使用。

1.直接当做服务器使用

         Jetty和Tomcat一样,可以直接当做服务器使用。我这里下载的是最新的Jetty9,直接解压就可以了。插一句话,其实学习这些框架知识,最好的资源就是官方网站的说明文档。虽然是英文的,但是使用的都是简单地句子,应该不是很大的问题。我学习这些基本都是参考的说明文档,做一下笔记,方便自己将来使用的时候查阅。

         官方文档中开始的时候这样写道:

Jetty is an open-source project providing an HTTP server, HTTP client, and javax.servlet container.

This guide is in two parts.

The first part emphasizes beginning to use Jetty. It provides information about downloading Jetty, changing things like the port Jetty runs on, adjusting logging levels, and configuring many of the most common servlet container features such as JNDI, JMX, and session management.

The second part describes advanced uses of Jetty, providing in depth coverage of specific features like our highly scalable async client, proxy servlet configuration, the Jetty Maven plugin, and using Jetty as an embedded server. The advanced section includes tutorials, howtos, videos, and reference materials.”

应该不是很难看懂吧,主要说了Jetty入门使用,Jetty作为容器特性比如JNDI, JMX, Session Management等等,然后继续深入的讲解Jetty的一些知识,比如Jetty的高度可扩展性的异步客户端实现机制,代理服务器的配置,Maven的配置和使用Jetty作为嵌入式服务器的应用等等。

         先启动服务器:

         直接解压之后,便可以运行,不过之前需要我们在环境变量中PATH添加JDK的路径,之后还需要新建JAVA_HOME,Value是JDK的安装路径,因为在Tomcat的时候,没有添加这一个变量,就无法启动,不知道这个会不会,还是添加上比较好。

         启动命令:java –jar start.jar jetty.port=8001(可以写到一个bat批处理文件,或者是Shell脚本)

         我们会发现Jetty的主页是没有任何东西的,因为根目录中是没有任何东西的,所以需要我们新建一个HTML文件,便可以看到。打开浏览器便可以看到响应的结果。

         可能遇到的问题:

         直接双击了start.jar, 但是无法关掉服务器。

         开始的时候我直接双击的start.jar,也是可以运行的,但是问题就出来了,我不确定是否运行,便打开浏览器运行,发现服务器已经在运行,但是如何终止呢,我找了半天也没找到,最后在进程控制中强制咔掉了JAVA的所有服务,才终止了服务器的运行。这个时候服务器的根目录在jetty\demo-base\webapps\ROOT中,建议还是不要这样运行,

         JDK环境配置问题

         上面知识一个简单地服务器,但是只能够运行HTML文件,所以我们小心点测试一下JSP页面怎样,会发现虽然可以启动服务器,但是运行代码的时候报错:

HTTP ERROR 500

Problem accessing /. Reason:

    Server Error

Caused by:

org.apache.jasper.JasperException: PWC6345: There is an error in invoking javac.  A full JDK (not just JRE) is required

         at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:92)

         at org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:378)

         我找了一下资料,说是什么使用的是系统的JDK,所以在运行的时候找不到我们安装的JDK目录,因为在安装JDK的时候,会网C盘系统中复制Java.exe, 这样系统运行的时候优先使用系统的,而导致找不到我们安装的完整版的JDK,所以就无法运行了,出现了A full (not just jre) is required. 的系统错误。

         其实Jetty中有关于系统运行之前的配置信息,保存在同目录下面的start.ini文件中,里面有关于开启JSP服务的知识,将最后面一句前面的#删除即可

#

# Initialize module jsp

#

--module=jsp

# JSP Configuration

# To use an non-jdk compiler for JSP compilation uncomment next line

#-Dorg.apache.jasper.compiler.disablejsr199=true

改成: -Dorg.apache.jasper.compiler.disablejsr199=true

         这样便可以直接运行JSP文件了,终止程序的话,退出当前的窗口即可。我们可以讲系统的日志输入到文件中 java –jar start.jar jetty.port=8001 > server.log

2.关于Jetty的一些参数设置

         jetty.home: The property that defines the location of the jetty distribution, its libs, default modules and default XML files (typically start.jar, lib, etc)

         jetty.base: The property that defines the location of a specific instance of a jetty server, its configuration, logs and web applications (typically start.ini, start.d, logs and webapps)

         jetty.port: jetty start port, 这一个配置在start.d/http.ini文件中,可以修改

         java –jar start.jar –add-to-startd=httpd

3.使用Maven配置

<dependency>

  <groupId>org.eclipse.jetty</groupId>

  <artifactId>jetty-project</artifactId>

  <version>9.1.3-SNAPSHOT</version>

</dependency>

         也许你还不知道Maven,其实我也是半瓶水,一般在里linux上比较好用,他会根据依赖的包的关系,自动下载相应的包,我们只需要dependency配置文件。

4.Jetty的嵌入式服务器

         在Java应用中使用Jetty作为嵌入式服务器,我们可下载一个完整版的JAR包,地址是http://central.maven.org/maven2/org/eclipse/jetty/aggregate/jetty-all/.

此外还要添加servlet.jar

源代码:

//TestMain.java

package jetty_test;

 

import org.eclipse.jetty.server.Server;

import org.eclipse.jetty.server.ServerConnector;

import org.eclipse.jetty.server.handler.DefaultHandler;

 

public class TestMain {

 

    public static void main(String[] args) throws Throwable {

        // TODO Auto-generated method stub

        Server serverJetty = new Server();

        ServerConnector connector_one = new ServerConnector(serverJetty);

        ServerConnector connector_two = new ServerConnector(serverJetty);

        connector_one.setPort(8000);

        connector_two.setPort(8001);

        serverJetty.setConnectors(new ServerConnector[]{connector_one, connector_two});

        serverJetty.setHandler(new MyHandler());

        serverJetty.start();

        serverJetty.join();    

    }

}

/*

 * author yang

 * MyHandler.java

 */

package jetty_test;

 

import java.io.IOException;

import java.util.Date;

 

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

import org.eclipse.jetty.server.Handler;

import org.eclipse.jetty.server.Request;

import org.eclipse.jetty.server.Server;

 

public class MyHandler implements Handler {

    @Override

    public void handle(String target, Request baseRequest, HttpServletRequest request,

            HttpServletResponse response) throws IOException, ServletException {

        // TODO Auto-generated method stub

        System.out.println("target:" + target);

        System.out.println(request.getRequestURL().toString());

       

        response.setCharacterEncoding("utf-8");

        response.setContentType("text/html;charset=utf-8");

        response.setStatus(HttpServletResponse.SC_OK);

        response.getWriter().write("<b>yangtengfei</b>"+ (new Date()).toLocaleString());

        response.flushBuffer();

 

    }

    /*

    省略自动生成的代码

    */

}

测试可以哎,这就是将WebServer嵌入到应用程序中,其中最为关键的就是Handle,也就是分发处理请求,传入的主要参数HttpServletRequest & HttpServletResponse,将结果传入到response即可。

对于一些比较特殊的情况,在嵌入式应用程序,可能需要配置Jetty服务器的参数,我们可以使用jetty.xml加载配置信息到XmlConfiguration中,然后配置到Server,我还是没有配置成功,建议使用Java语言进行配置,不适用XML文件了。

5.理论性的介绍

         因为我们已经学会简单地使用Jetty服务器了,那么为什么还要去了解Jetty的理论知识。其实学习一部分知识,不仅仅要学会如何使用,还要知道这个框架知识的优缺点,什么情况下使用这部分的知识应用于实际。这里的Jetty服务器有什么好的地方?

         Jetty是一个使用Java实现的、开元的基于标准的,并且具有丰富功能的HTTP服务器和 Web 容器。Jetty的用途:传统的Web服务器、动态的内容服务器、嵌入到Java应用。

         特征

         易用性:使用API 或者是XML配置即可,默认配置可以满足绝大部分需求,将Jetty可嵌入到应用程序中,切代码量非常的少。

         可扩展性:在Ajax的Web 2.0应用程序中,每一个连接需要保持很长的时间,这样的线程和内存消耗会急剧增加,从而导致整个系统因为单一组件陷入瓶颈而影响程序的整体性能。Jetty非常轻松的解决了这个问题:

         即使有大量服务请求的情况支架,系统的性能也可以保持在一个可以接受的状态;利用Configuration机制来处理大量的用户请求以及时间比较长的连接。同时Jetty设计了非常良好的接口,所以我们可以根据自己的而需要进行修改。

         易嵌入型:就是将Jetty嵌入到Java应用程序中,也就是嵌入式Web服务器。

6.Jetty 的Configuration机制

         在Web 2.0时代中的Ajax技术中,一个核心对象就是XMLHttpRequest对象,这个对象支持异步请求(异步请求:当客户端发送一个请求到服务器端的时候,客户端不必一直等待服务器的响应。这样就不会造成真个页面的刷新,给用户带来更好的用户体验,当服务器返回响应的时候,客户端利用一个JavaScript函数对返回值进行处理,更新页面上的部分元素的值)这种请求只是在很小的一部分情况下才会发生。如果实现这一种服务器有了响应之后客户端会立马知道的功能呢?有两种方式:轮询,也就是让浏览器每隔一段时间就请求服务器;Comet,维持服务器和客户端的长连接机制。

         轮询的方式最大的缺点就是产生大量的传输浪费。因为很多的请求时无效的请求,占用大量的带宽资源,加剧了服务器端的负载,尤其是针对邮件系统,需要个很长的时间才会更新。如果设置的时间间隔很长的话,客户端就不能得到及时的响应。

         使用Comet技术的话,客户端就必须保证一个长连接。一般情况下,服务器的每一个Servlet都会独自占用一个线程,这样就会导致服务器端有大量的线程同时存在,当客户端非常多的时候,就会对服务器的处理能力造成极大的挑战。

         在Java中使用Java语言的非阻塞IO技术处理并发的大量连接。Jetty处理长连接机制:一个被称为Configuration的特性,Jetty可以使用一个线程同时处理多个客户端发送的异步请求:

public class ChatContinuation extends HttpServlet{

         public void doPost(HttpServletRequest request, HttpServletResponse response){

                   postMessage(request, response);

         }

         private void postMessage(HttpServletRequest, HttpServletResponse response){

                   HttpSession session  = request.getSession(true);

                   People people = (People)session.getConfiguration(request,this);

                   If(!people.hasEvent()){

         Continuation continuation = Continuation.getContinuation(request,this);

         people.setContinuation(continuation);

         continuation.suspend(1000);//这个时候,线程是挂起,是可以处理其他的请求的,大大提高了程序的并发性能,使长连接获得很好的扩展性。

}

people.setContinuation(null);

people.sendEvent(response);

         }

}

         如果不使用Continuation机制的话,只能够使用线程挂起进行等待,参考代码如下:

public class Chat extends HttpServlet{

         public void doPost(HttpServletRequest request, HttpServletResponse response){

postMessage(request,response);

}

private void postMessage(HttpServletRequest request, HttpServletResponse response){

         HttpSession session = request.getSession(true);

         People people = (People)session.getAttribute(session.getId());

         while(!people.hasEvent()){

                   try{

         Thread.sleep(1000);

}catch(InterruptException e){

         e.printStack();

}

         }

}

}

Jetty的Continuation机制:

         使用Continuations机制,Jetty必须配置为使用它的SelectChannelConnector处理请求,这个Connector构建在java.nio.API之上,允许它维持每个连接而不用小号一个县城。当使用SelectChannelConnector时, ContinuationSupport.getContinuation()提供一个SelectChannelConnector.RetryContinuation实例。在RetryContinuation上调用suspend函数的时候,会抛出运行时的异常。该异常传递到filter链,最后被SelectChannelConnector捕获。但是不会发送异常到客户端,而是将请求维持在未决Continuation队列里面,则HTTP连接保持开放。这样用来服务请求的线程返回给ThreadPool,然后又可以用来服务其他的请求。暂停的请求停留在未决Continuation队列里直到指定的过期时间,或者是在他的Continuation上调用resume()。当其中的任何一个条件被触发的时候,请求就会被重新提交给Servlet(通过Filter链),整个请求过程被重播,知道RetryRequest异常不在抛出,然后按照正常的情况执行。

 

追寻梦的飞飞

2014.03.24 于广州 

posted on 2014-03-24 20:41  追梦的飞飞  阅读(2761)  评论(0编辑  收藏  举报