关于Tomcat的Pipeline机制
2016-02-16 15:16
597 查看
看了Tomcat的pipeline和valve的机制。试着写了一个简单的结构,记录一下。
pipeline--包含了改容器要唤醒的所有任务。每一个valve表示了一个特定的任务。容器的pipeline还有一个basic valve。valve可以自由添加一个或者多个。
类似于servlet过滤器,一个pipeline就像一个过滤链,每一个valve像一个过滤器。跟过滤器一样,一个valve可以操作传递给它的request和response方法。让一个阀门完成了处理,则进一步处理流水线中的下一个阀门,基本阀门总是在最后才被调用,但是会最先执行里面的方法。 一个容器可以实现pipeline接口。当容器的invoke方法被调用的时候,容器将会处理流水线中的阀门,并一个接一个的处理,直到所有的阀门都被处理完毕。
这个例子我们只有一个容器wrapper, servlet的封装类。它有一个servletClass属性来记录实际的servlet的名称。
首先,这个是启动类:
HeaderLoggerValve和ClientIPLoggerValve是两个阀门,用来打印请求头和用户ip.
然后我们来看这个SimpleWrapper.
这个是谁呢,这个就是下面要说的SimplePipeline的basic valve,它是用来调用真实servlet的service方法的
SimpleWrapper里面有一个SimplePipeline,调simpleWrapper的invoke的话,就会调用它的invoke方法。SimplePipeline是这样的。
这个类里面有一个内部类SimplePipelineValveContext。它继承了ValveContext,里面很重要的一个方法是invokeNext.它是这样工作滴。首先有一个请求来了,wrapper会调用它,这个时候初始化一个它的实例。这个时候stage=0,subscript=0,然后加载所有的valve。依次调用它们。最后basic valve。但是哦,我们看到前面两个valve的invoke方法,都是先valveContext.invokeNext(request, response); 所以其实是basic里的invoke方法最先被执行,然后是valve2,最后是valve1.
下面看下两个valve类
这样就实现了pipeline的机制了。
代码参考:
how tomcat works
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 instance private 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()); } @Override public synchronized void addValve(Valve valve) { pipeline.addValve(valve); } @Override public Servlet allocate() throws ServletException { // Load and initialize our instance if necessary if (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 used if (loader == null) { throw new ServletException("No loader."); } ClassLoader classLoader = loader.getClassLoader(); // Load the specified servlet class from the appropriate class loader Class 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 itself try { servlet = (Servlet) classClass.newInstance(); } catch (Throwable e) { throw new ServletException("Failed to instantiate servlet"); } // Call the initialization method of this servlet try { servlet.init(null); } catch (Throwable f) { throw new ServletException("Failed initialize servlet."); } return servlet; } @Override public 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; @Override 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); } } catch (ServletException e) { } } @Override public String getInfo() { return null; } @Override public Container getContainer() { return container; } @Override public 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 Valves protected Valve valves[] = new Valve[0]; public void setContainer(Container container) { this.container = container; } @Override public Valve getBasic() { return basic; } @Override public void setBasic(Valve valve) { this.basic = valve; ((Contained) valve).setContainer(container); } @Override public 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; } } @Override public Valve[] getValves() { return valves; } @Override public void invoke(Request request, Response response) throws IOException, ServletException { // Invoke the first Valve in this pipeline for this request (new SimplePipelineValveContext()).invokeNext(request, response); } @Override public 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; @Override public String getInfo() { return null; } @Override public void invokeNext(Request request, Response response) throws IOException, ServletException { int subscript = stage; stage = stage + 1; // Invoke the requested Valve for the current request thread if (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; @Override public 4000 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("------------------------------------"); } @Override public String getInfo() { return null; } @Override public Container getContainer() { return container; } @Override public void setContainer(Container container) { this.container = container; } }
public class ClientIPLoggerValve implements Valve, Contained { protected Container container; @Override 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("------------------------------------"); } @Override public String getInfo() { return null; } @Override public Container getContainer() { return container; } @Override public void setContainer(Container container) { this.container = container; } }
这样就实现了pipeline的机制了。
代码参考:
how tomcat works
相关文章推荐
- Maven学习 (五) Elipse中发布一个Maven项目到Tomcat
- windows杀掉某端口进程
- 将eclipse项目部署到tomcat根目录
- java获取tomcat路径
- IDE【1】(intellij idea的tomcat的配置)
- Intellij15 + JRebel6.2.3 + Tomcat7实现热部署
- java.lang.UnsatisfiedLinkError: D:\Tomcat\apache-tomcat-7.0.37\bin\tcnative-1.dll: Can't load AMD 6
- Linux下安装与配置基于nginx的tomcat负载均衡和集群
- Linux CentOS 6.5中安装与配置Tomcat-8方法
- 基于Tomcat7、Java、WebSocket的服务器推送聊天室
- Linux下Tomcat重新启动
- CentOS下配置Tomcat开机自启动
- MyEclipse + Tomcat + Maven + SVN 项目完整开发环境搭建
- 多个tomcat共存是修改端口
- Java 和tomcat环境配置笔记
- 02-CentOS下安装jdk+mysql+tomcat
- 1.3 linux系统安装tomcat
- Could not publish server configuration for Tomcat v6.0 Server at localhost.
- Tomcat 中的 Log
- 在 Tomcat 中使用 JSTL