您的位置:首页 > 运维架构 > Tomcat

关于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的名称。

首先,这个是启动类:

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: