关于Tomcat的Pipeline机制

来源:互联网 发布:l800清零软件 编辑:程序博客网 时间:2024/05/01 14:36
看了Tomcat的pipeline和valve的机制。试着写了一个简单的结构,记录一下。
pipeline--包含了改容器要唤醒的所有任务。每一个valve表示了一个特定的任务。容器的pipeline还有一个basic valve。valve可以自由添加一个或者多个。
类似于servlet过滤器,一个pipeline就像一个过滤链,每一个valve像一个过滤器。跟过滤器一样,一个valve可以操作传递给它的request和response方法。让一个阀门完成了处理,则进一步处理流水线中的下一个阀门,基本阀门总是在最后才被调用,但是会最先执行里面的方法。 一个容器可以实现pipeline接口。当容器的invoke方法被调用的时候,容器将会处理流水线中的阀门,并一个接一个的处理,直到所有的阀门都被处理完毕。


这个例子我们只有一个容器wrapper, servlet的封装类。它有一个servletClass属性来记录实际的servlet的名称。


首先,这个是启动类:

public final class Bootstrap5 {  public static void main(String[] args) {    HttpConnector connector = new HttpConnector();    Wrapper wrapper = new SimpleWrapper();    wrapper.setServletClass("com.m7.webserver.test2.PrimitiveServlet");    Loader loader = new SimpleLoader();    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();    }  }}

HeaderLoggerValve和ClientIPLoggerValve是两个阀门,用来打印请求头和用户ip.


然后我们来看这个SimpleWrapper.

public class SimpleWrapper implements Wrapper, Pipeline {// the servlet instanceprivate Servlet instance = null;private String servletClass;private Loader loader;private String name;private SimplePipeline pipeline = new SimplePipeline(this);protected Container parent = null;public SimpleWrapper() {pipeline.setBasic(new SimpleWrapperValve());}@Overridepublic synchronized void addValve(Valve valve) {pipeline.addValve(valve);}@Overridepublic Servlet allocate() throws ServletException {// Load and initialize our instance if necessaryif (instance == null) {try {instance = loadServlet();} catch (ServletException e) {throw e;} catch (Throwable e) {throw new ServletException("Cannot allocate a servlet instance", e);}}return instance;}private Servlet loadServlet() throws ServletException {if (instance != null)return instance;Servlet servlet = null;String actualClass = servletClass;if (actualClass == null) {throw new ServletException("servlet class has not been specified");}Loader loader = getLoader();// Acquire an instance of the class loader to be usedif (loader == null) {throw new ServletException("No loader.");}ClassLoader classLoader = loader.getClassLoader();// Load the specified servlet class from the appropriate class loaderClass classClass = null;try {if (classLoader != null) {classClass = classLoader.loadClass(actualClass);}} catch (ClassNotFoundException e) {throw new ServletException("Servlet class not found");}// Instantiate and initialize an instance of the servlet class itselftry {servlet = (Servlet) classClass.newInstance();} catch (Throwable e) {throw new ServletException("Failed to instantiate servlet");}// Call the initialization method of this servlettry {servlet.init(null);} catch (Throwable f) {throw new ServletException("Failed initialize servlet.");}return servlet;}@Overridepublic void invoke(Request request, Response response) throws IOException,ServletException {pipeline.invoke(request, response);}...}

这个是谁呢,这个就是下面要说的SimplePipeline的basic valve,它是用来调用真实servlet的service方法的

public class SimpleWrapperValve implements Valve, Contained {protected Container container;@Overridepublic 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 requesttry {servlet = wrapper.allocate();if (hres != null && hreq != null) {servlet.service(hreq, hres);} else {servlet.service(sreq, sres);}} catch (ServletException e) {}}@Overridepublic String getInfo() {return null;}@Overridepublic Container getContainer() {return container;}@Overridepublic void setContainer(Container container) {this.container = container;}}

SimpleWrapper里面有一个SimplePipeline,调simpleWrapper的invoke的话,就会调用它的invoke方法。SimplePipeline是这样的。

public class SimplePipeline implements Pipeline {public SimplePipeline(Container container) {setContainer(container);}// The basic Valve (if any) associated with this Pipeline.protected Valve basic = null;// The Container with which this Pipeline is associated.protected Container container = null;// the array of Valvesprotected Valve valves[] = new Valve[0];public void setContainer(Container container) {this.container = container;}@Overridepublic Valve getBasic() {return basic;}@Overridepublic void setBasic(Valve valve) {this.basic = valve;((Contained) valve).setContainer(container);}@Overridepublic void addValve(Valve valve) {if (valve instanceof Contained)((Contained) valve).setContainer(this.container);synchronized (valves) {Valve results[] = new Valve[valves.length + 1];System.arraycopy(valves, 0, results, 0, valves.length);results[valves.length] = valve;valves = results;}}@Overridepublic Valve[] getValves() {return valves;}@Overridepublic void invoke(Request request, Response response) throws IOException,ServletException {// Invoke the first Valve in this pipeline for this request(new SimplePipelineValveContext()).invokeNext(request, response);}@Overridepublic void removeValve(Valve valve) {}// this class is copied from org.apache.catalina.core.StandardPipeline// class's// StandardPipelineValveContext inner class.protected class SimplePipelineValveContext implements ValveContext {protected int stage = 0;@Overridepublic String getInfo() {return null;}@Overridepublic void invokeNext(Request request, Response response)throws IOException, ServletException {int subscript = stage;stage = stage + 1;// Invoke the requested Valve for the current request threadif (subscript < valves.length) {valves[subscript].invoke(request, response, this);} else if ((subscript == valves.length) && (basic != null)) {basic.invoke(request, response, this);} else {throw new ServletException("No valve");}}} // end of inner class}

这个类里面有一个内部类SimplePipelineValveContext。它继承了ValveContext,里面很重要的一个方法是invokeNext.它是这样工作滴。首先有一个请求来了,wrapper会调用它,这个时候初始化一个它的实例。这个时候stage=0,subscript=0,然后加载所有的valve。依次调用它们。最后basic valve。但是哦,我们看到前面两个valve的invoke方法,都是先valveContext.invokeNext(request, response); 所以其实是basic里的invoke方法最先被执行,然后是valve2,最后是valve1.


下面看下两个valve类


public class HeaderLoggerValve implements Valve, Contained {protected Container container;@Overridepublic void invoke(Request request, Response response,ValveContext valveContext) throws IOException, ServletException {// Pass this request on to the next valve in our pipelinevalveContext.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);}} elseSystem.out.println("Not an HTTP Request");System.out.println("------------------------------------");}@Overridepublic String getInfo() {return null;}@Overridepublic Container getContainer() {return container;}@Overridepublic void setContainer(Container container) {this.container = container;}}

public class ClientIPLoggerValve implements Valve, Contained {  protected Container container;  @Overridepublic 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("------------------------------------");  }  @Overridepublic String getInfo() {    return null;  }  @Overridepublic Container getContainer() {    return container;  }  @Overridepublic void setContainer(Container container) {    this.container = container;  }}

这样就实现了pipeline的机制了。


代码参考:

how tomcat works

0 0
原创粉丝点击