`
dicmo
  • 浏览: 66900 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Coder 爱翻译 How Tomcat Works 第五章 第二部分

    博客分类:
  • j2ee
阅读更多
The Pipeline Interface

我们提到的Pipeline接口的第一个方法invoke方法,这个方法是容器用来调用在pipeline中的valve和basic valve的。Pipeline接口允许你使用它的addValve方法来添加一个新的valve和使用removeValve方法来移除一个valve。最后,你使用它的setBasic方法给pipeline来指定一个basic valve和它的getBasic方法获取basic valve。basic valve是在最后被调用的,它负责处理request和相应的response。下面是Pipeline接口:
Listing 5.3: The Pipeline interface   
 
package org.apache.catalina; 
import java.io.IOException; 
 
import javax.servlet.ServletException;
public interface Pipeline { 
   public Valve getBasic(); 
   public void setBasic(Valve valve); 
   public void addValve(Valve valve); 
   public Valve[] getValves(); 
   public void invoke(Request request, Response response) 
     throws IOException, ServletException; 
   public void removeValve(Valve valve); 
} 


The Valve Interface

Valve接口代表了一个valve,这个组件负责处理一个request。这个接口有两个方法:invoke和getInfo。invoke方法在前面已经讨论了。getInfo方法返回关于valve实现的信息。

Listing 5.4: The Valve interface   
package org.apache.catalina; 
import java.io.IOException; 
import javax.servlet.ServletException; 
 
public interface Valve { 
   public String getInfo(); 
   public void invoke(Request request, Response response, 
     ValveContext context) throws IOException, ServletException;
}


The ValveContext Interface

这个接口有两个方法:invokeNext方法在前面讨论了,getInfo方法返回ValveContext实现的信息。
Listing 5.5: The ValveContext interface   
 
package org.apache.catalina;
import java.io.IOException; 
import javax.servlet.ServletException; 
 
public interface ValveContext { 
   public String getInfo(); 
   public void invokeNext(Request request, Response response) 
     throws IOException, ServletException; 
 } 


The Contained Interface

一个valve类可以选择性地实现org.apache.catalina.Contained接口。这个接口表明实现了该接口的类是最多和一个容器实例相关联的。
Listing 5.6: The Contained interface   
 
package org.apache.catalina; 
public interface Contained { 
   public Container getContainer(); 
   public void setContainer(Container container);
}


The Wrapper Interface

org.apache.catalina.Wrapper接口代表了一个wrapper。一个wrapper代表了一个独立的servlet定义的容器。Wrapper接口继承自Container,再添加了一些其他方法。Wrapper的实现负责管理它们底层的servlet类的servlet生命周期。例如:调用servlet的init,service和destroy方法。一个wrapper是容器的最底层,你就不能向它里面添加子容器。如果你向它里面调用addChild方法添加子容器,这时Wrapper会抛出一个IllegalArgumantException异常。

Wrapper接口的重要方法包括:allocate和load。allocate方法分配一个这wrapper所代表的servlet初始化实例。allocate方法必须考虑到这个servlet是否是实现了javax.servlet.SingleThreadModel接口,我们在后面十一章讨论。load方法加载和实例化一个wrapper所代表的servlet。
public javax.servlet.Servlet allocate() throws
javax.servlet.ServletException; 

public void load() throws javax.servlet.ServletException;


The Context Interface

一个context是代表了一个web应用的容器。一个context通常有一个或多个子容器。
重要的方法包括addWrapper,createWrapper等。这接口将在十二章详细讨论。

The Wrapper Application

这个应用程序演示怎么编写一个小的容器模块。核心类是ex05.pyrmont.core.SimpleWrapper,一个Wrapper接口的实现。SimpleWrapper类包含了一个Pipeline(实现了ex05.pyrmont.core.SimplePipeline类)和使用Loader(实现了ex05.pyrmont.core.SimpeLoader)来加载servlet。Pipeline包含了一个basic valve(ex05.pyrmont.core.SimpleWrapperValve)和两个valve(ex05.pyrmont.core.ClientIPLoggerValve 和ex05.pyrmont.core.HeaderLoggerValve)

类图:


wrapper包装了在前几章使用过的ModernServlet。这个应用程序证实了你可以使用一个只有一个wrapper组成的servlet容器。

ex05.pyrmont.core.SimpleLoader

在容器中加载servlet类的任务分配给Loader来完成这个功能。在这个应用中,SimpleLoader类就是Loader实现。它知道servlet类的路径,它的getClassLoader方法返回一个java.lang.ClassLoader实例来搜索servlet类的路径。SimpleLoader类声明了三个变量。第一个是WEB_ROOT,它指向能找到servlet类所在的目录。
public static final String WEB_ROOT = 
   System.getProperty("user.dir") + File.separator  + "webroot";

其他两个变量时ClassLoader和Container的对象引用。
ClassLoader classLoader = null; 
Container container = null;

SimpleLoader类的构造函数初始化类加载器,并返回给SimpleWrapper实例。
public SimpleLoader() { 
     try { 
       URL[] urls = new URL[l]; 
       URLStreamHandler streamHandler = null; 
       File classPath = new File(WEB_ROOT); 
       String repository = (new URL("file", null, 
classPath.getCanonicalPath() + File.separator)).toString() ; 
       urls[0] = new URL(null, repository, streamHandler); 
       classLoader = new URLClassLoader(urls); 
     }catch (IOException e) { 
       System.out.println(e.toString() ); 
     } 
}

构造函数里面的代码用来初始化应用程序中的类加载器。
容器的变量代表了与这个加载器相关联的容器。Loader会在第八章讨论。

ex05.pyrmont.core.SimplePipeline

SimplePipeline类实现了org.apache.catalina.Pipeline接口。最重要的方法是invoke方法,里面包含一个内部类SimplePipelineValveContext。SimplePipelineValveContext实现了org.apache.catalina.ValveContext接口。

ex05.pyrmont.core.SimpleWrapper

这个类实现了org.apache.catalina.Wrapper接口和提供了allocate和load方法的实现。它还声明了下面的变量:
private Loader loader; 
protected Container parent = null;

loader变量是一个Loader,它用来加载servlet类。parent变量代表一个这个wrapper的父容器。这意味着wrapper可以是另一个容器的子容器(就像是Context的子容器)。注意一下getLoader方法:
public Loader getLoader() { 
   if (loader != null) 
     return (loader); 
   if (parent != null) 
     return (parent.getLoader()); 
   return (null); 
}

getLoader方法返回一个用来加载servlet类的Loader。如果wrapper和一个Loader相关联,这个Loader将被返回。如果没有相关的,就返回Loader的父容器。如果没有preant变量,getLoader就返回null。

SimpleWrapper类有一个pipeline并在pipeline中设置了一个basic valve。
public SimpleWrapper() { 
 	pipeline.setBasic(new SimpleWrapperValve()); 
} 

这里,pipeline是一个在类中声明的SimplePipeline实例:
private SimplePipeline pipeline = new SimplePipeline(this);


ex05.pyrmont.core.SimpleWrapperValve

SimpleWrapperValve类是basic valve用来为SimpleWrapper类处理请求。它实现了org.apache.catalina.Valve接口和org.apache.catalina.Contained接口。在SimpleWrapperValve中最重要的方法invoke方法。
Listing 5.9: The SimpleWrapperValve class's invoke method   
 
public void invoke(Request request, Response response, 
   ValveContext valveContext) 
   throws IOException, ServletException { 
 
   SimpleWrapper wrapper = (SimpleWrapper) getContainer(); 
   ServletRequest sreq = request.getRequest(); 
   ServletResponse sres = response.getResponse(); 
   Servlet servlet = null; 
   HttpServletRequest hreq = null; 
   if (sreq instanceof HttpServletRequest)
     hreq = (HttpServletRequest) sreq; 
   HttpServletResponse hres = null; 
   if (sres instanceof HttpServletResponse) 
     hres = (HttpServletResponse) sres; 
   // Allocate a servlet instance to process this request 
   try { 
     servlet = wrapper.allocate(); 
     if (hres!=null && hreq!=null) { 
       servlet.service(hreq, hres); 
     } 
     else { 
       servlet.service(sreq, sres)
     hreq = (HttpServletRequest) sreq; 
   HttpServletResponse hres = null; 
   if (sres instanceof HttpServletResponse) 
     hres = (HttpServletResponse) sres; 
   // Allocate a servlet instance to process this request 
   try { 
     servlet = wrapper.allocate(); 
     if (hres!=null && hreq!=null) { 
       servlet.service(hreq, hres); 
     } 
     else { 
       servlet.service(sreq, sres)
     } 
   } catch (ServletException e) { 
   } 
}

因为SimpleWrapperValve是作为一个basic valve,所以它的invoke方法不需要调用传递给它的ValveContext的invokeNext方法。invoke方法调用SimpleWrapper类的allocate方法获取一个代表wrapper的servlet实例。注意wrapper中pipeline的basic valve调用servlet的service方法。而不是调用wrapper它自己。

ex05.pyrmont.valves.ClientIPLoggerValve

ClientIPLoggerValve类是一个valve,它是打印客户端的IP地址到控制台。
Listing 5.10: The ClientIPLoggerValve class   
package ex05.pyrmont.valves; 
 
import java.io.IOException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletException; 
import org.apache.catalina.Request; 
import org.apache.catalina.Response;
import org.apache.catalina.Valve; 
import org.apache.catalina.ValveContext; 
import org.apache.catalina.Contained; 
import org.apache.catalina.Container; 
 
public class ClientIPLoggerValve implements Valve, Contained { 
    protected Container container; 
    public void invoke(Request request, Response response, 
    ValveContext valveContext) throws IOException, ServletException { 
    // Pass this request on to the next valve in our pipeline 
    valveContext.invokeNext(request, response); 
    System.out.println("Client IP Logger Valve"); 
    ServletRequest sreq = request.getRequest(); 
    System.out.println(sreq.getRemoteAddr());
    System, out.println("-----------------------------------"); 
   } 
 	 public String getInfo() { 
     	return null; 
  	} 
  	 public Container getContainer() { 
     return container; 
   }
   public void setContainer(Container container) { 
     this.container = container; 
   } 
}

注意invoke方法。第一件要做的事是invoke方法调用valve context 的invokeNext方法来调用pipeline中的下一个valve。然后打印几行字符串,包括请求对象的getRemoteAddress方法的输出。

ex05.pyrmont.valves.HeaderLoggerValve

这个类和ClientIPLoggerValve类相似。HeaderLoggerValve类是打印请求头部信息到控制台。
Listing 5.11: The HeaderLoggerValve class   
 
package ex05.pyrmont.valves; 
 
import java.io.IOException; 
import java.util.Enumeration; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServletRequest; 
import org.apache.catalina.Request;
import org.apache.catalina.Response; 
import org.apache.catalina.Valve; 
import org.apache.catalina.ValveContext; 
import org.apache.catalina.Contained; 
import org.apache.catalina.Container; 
 
public class HeaderLoggerValve implements Valve, Contained {
protected Container container; 
public void invoke(Request request, Response response, 
    ValveContext valveContext) throws IOException, ServletException { 
    // Pass this request on to the next valve in our pipeline 
    valveContext.invokeNext(request, response); 
    System.out.println("Header Logger Valve"); 
    ServletRequest sreq = request.getRequest(); 
    if (sreq instanceof HttpServletRequest) { 
      HttpServletRequest hreq = (HttpServletRequest) sreq; 
      Enumeration headerNames = hreq.getHeaderNames();
   while (headerNames.hasMoreElements()) { 
         String headerName = headerNames.nextElement().toString(); 
         String headerValue = hreq.getHeader(headerName); 
         System.out.println(headerName + ":" + headerValue); 
       } 
 
     } 
     else 
       System.out.println("Not an HTTP Request"); 
 
     System.out.println ("-----------------------------------");
   } 
 
   public String getInfo() { 
     return null; 
   } 
   public Container getContainer() { 
     return container; 
   } 
   public void setContainer(Container container) {
     this.container = container; 
   } 
} 

再一次,注意invoke方法。第一件事是invoke方法调用valve context 的invokeNext方法调用pipeline的下一个valve。然后打印头部信息值。

ex05.pyrmont.startup.Bootstrap1

Bootstrap1类用来启动这个应用程序。
Listing 5.12: The Bootstrap1 class   
 
package ex05.pyrmont.startup; 
import ex05.pyrmont.core.SimpleLoader; 
import ex05.pyrmont.core.SimpleWrapper; 
import ex05.pyrmont.valves.ClientlPLoggerValve; 
import ex05.pyrmont.valves.HeaderLoggerValve; 
import org.apache.catalina.Loader; 
import org.apache.catalina.Pipeline; 
import org.apache.catalina.Valve; 
import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.http.HttpConnector; 
 
public final class Bootstrap1 { 
   public static void main(String[] args) { 
     HttpConnector connector = new HttpConnector(); 
    Wrapper wrapper = new SimpleWrapper(); 
     wrapper.setServletClass("ModernServlet"); 
     Loader loader = new SimpleLoader(); 
     Valve valve1 = new HeaderLoggerValve();
     Valve valve1 = new HeaderLoggerValve(); 
     Valve valve2 = new ClientIPLoggerValve(); 
     wrapper.setLoader(loader); 
     ((Pipeline) wrapper).addValve(valve1); 
     ((Pipeline) wrapper).addValve(valve2); 
     connector.setContainer(wrapper);
  try { 
       connector.initialize(); 
       connector.start(); 
       // make the application wait until we press a key. 
       System.in.read(); 
     } catch (Exception e) { 
       e.printStackTrace(); 
     } 
   }
}

创建一个HttpConnector和SimpleWrapper实例后,Bootstrap类的主方法把ModernServlet指配给SimpleWrapper的setServlet方法,通知wrapper,类的名字被加载。
wrapper.setServletClass("ModernServlet");

然后创建一个loader和两个valve,把loader设置给wrapper:
Loader loader = new SimpleLoader(); 
Valve valve1 = new HeaderLoggerValve(); 
Valve valve2 = new ClientIPLoggerValve(); 
wrapper.setLoader(loader);

两个valve被加入到wrapper的pipeline中:
((Pipeline) wrapper).addValve(valve1); 
((Pipeline) wrapper).addValve(valve2);

最后,wrapper被设置为连接器的容器,然后连接器初始化并启动。
  connector.setContainer(wrapper); 
     try { 
       connector.initialize(); 
       connector.start();

下面一行允许用户通过在控制台按Enter键停止应用程序。
// make the application wait until we press Enter. 
System.in.read();


Running the Application
  • 大小: 47.9 KB
3
0
分享到:
评论

相关推荐

    How tomcat works 中文版

    � jsp / servlet 开发人员,想了解 tomcat 内部机制的 coder ; � 想加入 tomcat 开发团队的 coder ; � web 开发人员,但对软件开发很有兴趣的 coder ; � 想要对 tomcat 进行定制的 coder 。 在阅读之前,希望...

    tomcat原理解析书(how-tomcat-works)中文版

    适合读者 1.jsp/servlet 开发人员,想了解 tomcat 内部机制的 coder;...2.想加入 tomcat 开发团队的 coder; 3.web 开发人员,但对软件开发很有兴趣的 coder; 4.想要对 tomcat 进行定制的 coder。

    Bad Programming Practices 101 Become a Better Coder by Learning How (Not) epub

    Bad Programming Practices 101 Become a Better Coder by Learning How (Not) to Program 英文epub 本资源转载自网络,如有侵权,请联系上传者或csdn删除 查看此书详细信息请在美国亚马逊官网搜索此书

    The Clean Coder

    Martin, "The Clean Coder: A Code of Conduct for Professional Programmers" Prentice Hall | 2011 | ISBN: 0137081073 | 256 pages | PDF | 6 MB Programmers who endure and succeed amidst swirling ...

    phpcoder.rar

    phpcoder安装包。 直接下载安装即可。

    HDL-Coder详细教程

    HDL-Coder详细教程,有详细例子,源于官方例程,中文教程

    php coder编辑器

    PHPCoder用于快速开发和调试PHP应用程序,它很容易扩展和定制,完全能够符合开发者的个性要求.PHPCoder是一个非常实用的,功能强大的编程环境,而且它是免费的!

    simulink hdl coder 用户手册pdf

    HDL CODER 的用户手册,学习hdl coder参考用书,详细介绍了用simulink开发fpga的过程

    MediaCoder答题器

    MediaCoder答题器

    Embedded Coder.rar

    texasinstrumentsc2000.mlpkginstall 支持TI的C2000系列工具包,要求MATLAB R2017a及其以上版本。 安装方法:打开matlab,调整路径到mlpkginstall文件所在目录;在current folder窗口里双击mlpkginstall文件即可开始...

    coder的建表语句

    coder的建表语句

    mediacoder专业版

    mediacoder 5685专业版,无普通版的限制

    MediaCoder使用说明文档

    MediaCoder使用说明文档, mediaCoder usermanual,

    range coder.pdf

    range coder, algorithm, compressing.

    MediaCoder.5755专业破解版

    MediaCoder行业版一款针对VOD及KTV视频点播行业开发的,用于转换和处理带有多音轨内容的视频节目的软件。它具备业界领先的视频编码引擎,在高性能转码的同时保持高画质,并通过丰富的视频滤镜增强画面视觉效果。作为...

    matlab Embedded Coder Getting Started Guide.pdf

    Embedded Coder用于产生嵌入式处理器、目标快速原型板和大规模生产中使用的微处理器的可读的、紧凑的、快速的C和C++代码。Embedded Coder支持附加的MATLAB Coder™和Simulink Coder™配置选项,以及对生成代码的功能...

    MediaCoder64位专业破解版

    MediaCoder-Premium-x64 MediaCoder是最早开始使用GPU进行视频编码加速的影音转码软件之一。通过将原本完全依赖CPU的计算工作转移到GPU上进行,H.264和H.265编码所需的时间被大幅缩短。

    AI自动生成SQL语句的开源代码 sqlcoder-main.zip

    开源的AI自动生成SQL语句源代码,这款...SQLCoder2和SQLCoder-7B模型已经向公众开放,大家可以直接拿来嵌入到你的业务开发应用中。大家到这个地址来下载模型:https://huggingface.co/defog/sqlcoder-7b-2,即可使用。

    Mediacoder 使用帮助文档

    Mediacoder 入门使用说明+各种编码常用参数设置。

Global site tag (gtag.js) - Google Analytics