首先我們知道tomcat是用java實現的Servlet規範的優秀的Servlet容器。
從上圖來看,tomcat對下接收了一個Http的網絡請求,對上調用了Web應用實現的其中一個Servlet接口。
tomcat調用應用的Servlet提供給應用一個ServletRequest和一個ServletResponse。
這就是tomcat實現的核心功能,這樣處理有什麼好處?
優點:容器與應用解耦。
缺點:接口固定了,擴展性變弱。
大致瞭解了tomcat容器與web應用之間的關係,接下來我們宏觀地認識下tomcat。
根據上面描述的這條數據線來講解一下tomcat的脈絡(下面內容是建立在對tomcat容器有基本瞭解的前提)
首先我們看看tomcat各個容器的包含關係
上面這張圖是tomcat的總體框架圖,我們對各組件做各簡單的說明:
server是管理service的,service是用來管理連接器(connector)和容器(engine)的
connector:連接器,監聽端口,讀取數據,解析數據並調用容器。
容器:根據請求路徑,映射到對應的servlet,加載對應的servlet,並調用service。
我寫了個簡單的應用,來模擬connector和容器間數據處理的,將這個應用弄明白,tomcat整體數據脈絡也就能弄清楚。
public interface Request {
String getUri();
void setInputStream(InputStream inputStream);
InputStream getInputStream();
}
public interface Response {
void setOutputStream(OutputStream outputStream);
OutputStream getOutputStream();
PrintWriter getPrintWriter();
}
public interface Servlet {
void service(Request request, Response response);
}
上面是模擬javax.servlet定義的Servlet,Request,Response接口,這個就是連接容器和應用的橋樑了,之所以沒有采用官方的,是因爲我們這裏主要目的是處理的脈絡,精簡的信息能確保我們不分散注意力到其他不相關的方面去,並且簡單的東西更方便大家理解。
public class Connector implements Runnable {
Container container;
public Container getContainer() {
return container;
}
public void setContainer(Container container) {
this.container = container;
}
@Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(8080,
20,
InetAddress.getByName("localhost"));
while (true) {
Socket socket = serverSocket.accept();
Request request = new ServletRequest();
request.setInputStream(socket.getInputStream());
Response response = new ServletResponse();
response.setOutputStream(socket.getOutputStream());
((ServletRequest) request).parseRequest(request);
container.invoke(request, response);
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void start() {
Thread t = new Thread(this);
t.start();
}
}
public class ServletRequest implements Request {
protected InputStream inputStream;
protected String uri;
protected String method;
protected String protocol;
void parseRequest(Request request) {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream()));
try {
String firstLine = bufferedReader.readLine();
String[] firstLineContent = firstLine.split(" ");
this.method = firstLineContent[0];
this.uri=firstLineContent[1];
this.protocol=firstLineContent[2];
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String getUri() {
return uri;
}
@Override
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
@Override
public InputStream getInputStream() {
return inputStream;
}
}
public class ServletResponse implements Response {
OutputStream outputStream;
@Override
public void setOutputStream(OutputStream outputStream) {
this.outputStream = outputStream;
}
@Override
public OutputStream getOutputStream() {
return outputStream;
}
@Override
public PrintWriter getPrintWriter() {
PrintWriter pw = new PrintWriter(outputStream);
return pw;
}
}
這裏我們先說一下ServletRequest與ServletResponse,這兩個分別實現了Request,Response接口,可直接作爲servlet的service的參數。
Connector,這個類裏面創建了一個線程,負責接收連接,創建ServletRequest,ServletResponse,解析請求數據,填充創建的對象,
我們再看看,connector與一個container關聯,處理完之後,調用了關聯的容器的invoke(Request,Response)。
public interface Pipeline {
Valve getBasic();
void setBasic(Valve valve);
Valve[] getValves();
void addValve(Valve valve);
void invoke(Request request, Response response);
}
public interface Valve {
void invoke(Request request, Response response, ValveContext valveContext);
}
public interface ValveContext {
void invokeNext(Request request, Response response);
}
public abstract class ValveBase implements Valve, Contained {
private Container container;
@Override
public Container getContainer() {
return container;
}
@Override
public void setContainer(Container container) {
this.container = container;
}
}
public class StandardPipeline implements Pipeline, Contained {
protected Valve basic;
protected Valve[] valves = new Valve[0];
protected Container container;
public StandardPipeline(Container container) {
this.container = container;
}
@Override
public Valve getBasic() {
return basic;
}
@Override
public void setBasic(Valve valve) {
this.basic = valve;
if (valve instanceof Contained) {
((Contained) valve).setContainer(this.container);
}
}
@Override
public Valve[] getValves() {
return null;
}
@Override
public void addValve(Valve valve) {
Valve[] t = new Valve[valves.length+1];
System.arraycopy(valves, 0, t, 0, valves.length);
t[t.length] = valve;
valves = t;
}
@Override
public void invoke(Request request, Response response) {
new StandardPipelineValveContext().invokeNext(request, response);
}
@Override
public Container getContainer() {
return container;
}
@Override
public void setContainer(Container container) {
this.container = container;
}
class StandardPipelineValveContext implements ValveContext {
private int stage=0;
@Override
public void invokeNext(Request request, Response response) {
int curr = stage;
stage++;
if (curr < valves.length) {
valves[curr].invoke(request, response, this);
} else {
basic.invoke(request, response, null);
}
}
}
}
每個容器都關聯着一個管道pipeline,上面代碼就是管道的一個簡單代碼模型。
管道運用到了責任鏈模式,位於鏈上的類均會調用。整個過程類似鏈表的遍歷從第一個節點逐個訪問到最後一個。
這樣做的好處,避免了調用與被調用,上層容器與下層容器之間的耦合,各自業務獨立處理,另外方便擴展。
public interface Contained {
Container getContainer();
void setContainer(Container container);
}
public interface Container {
String getName();
void setName(String name);
Container getChild(String name);
void addChild(Container container);
Container map(Request request);
void invoke(Request request, Response response);
}
public abstract class ContainerBase implements Container, Pipeline {
protected HashMap<String, Container> children = new HashMap();
protected Pipeline pipeline;
public ContainerBase() {
}
private String name;
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public Container getChild(String name) {
return children.get(name);
}
@Override
public void addChild(Container container) {
children.put(container.getName(), container);
}
@Override
public void invoke(Request request, Response response) {
pipeline.invoke(request, response);
}
@Override
public Valve getBasic() {
return pipeline.getBasic();
}
@Override
public void setBasic(Valve valve) {
pipeline.setBasic(valve);
}
@Override
public Valve[] getValves() {
return pipeline.getValves();
}
@Override
public void addValve(Valve valve) {
pipeline.addValve(valve);
}
}
public class Wrapper extends ContainerBase {
private String servletClass;
public Wrapper() {
this.pipeline = new StandardPipeline(this);
setBasic(new StandardWrapperValve());
}
@Override
public Container map(Request request) {
return null;
}
public String getServletClass() {
return servletClass;
}
public void setServletClass(String servletClass) {
this.servletClass = servletClass;
}
}
public class StandardWrapperValve extends ValveBase {
@Override
public void invoke(Request request, Response response, ValveContext valveContext) {
Wrapper wrapper = (Wrapper) getContainer();
String servletClassName = wrapper.getServletClass();
System.out.println("wrapper 處理");
try {
// 這裏爲了簡便,直接用了系統的加載器,實際情況是需要定義自己的加載器的
Class servletClass = getClass().getClassLoader().loadClass(servletClassName);
Servlet servlet = (Servlet) servletClass.newInstance();
servlet.service(request, response);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
public class Context extends ContainerBase {
public Context() {
this.pipeline = new StandardPipeline(this);
setBasic(new StandardContextValve());
}
@Override
public Container map(Request request) {
// 因爲匹配規則比較多,我們這裏僅使用uri的最後一個/之後的內容匹配
String uri = request.getUri();
String pattern = uri.substring(uri.lastIndexOf('/'));
return getChild(pattern);
}
}
public class StandardContextValve extends ValveBase {
@Override
public void invoke(Request request, Response response, ValveContext valveContext) {
Context context = (Context) getContainer();
System.out.println("context處理");
Wrapper wrapper = (Wrapper) context.map(request);
wrapper.invoke(request, response);
}
}
public class Host extends ContainerBase {
public Host() {
this.pipeline = new StandardPipeline(this);
setBasic(new StandardHostValve());
}
@Override
public Container map(Request request) {
return getChild("/mytmct");
}
}
public class StandardHostValve extends ValveBase {
@Override
public void invoke(Request request, Response response, ValveContext valveContext) {
Host host = (Host) getContainer();
System.out.println("host 處理");
Context context = (Context) host.map(request);
context.invoke(request, response);
}
}
public class Engine extends ContainerBase {
public Engine() {
this.pipeline = new StandardPipeline(this);
setBasic(new StandardEngineValve());
}
@Override
public Container map(Request request) {
return getChild("localhost");
}
}
public class StandardEngineValve extends ValveBase {
@Override
public void invoke(Request request, Response response, ValveContext valveContext) {
Engine engine = (Engine) getContainer();
System.out.println("engine 處理");
Host host = (Host) engine.map(request);
host.invoke(request, response);
}
}
整個結構關係,容器間通過組合方式建立關係,通過管道銜接調用,每個容器有一個管道,每個管道有一個基礎閥,而基礎閥基本上就是處理找到對應的子容器,並調用子容器的invoke方法。
直至調用了wrapper容器,該容器的管道的基礎閥加載servlet實現類,並調用service,獲取response,至此,tomcat數據脈絡我們大概弄明白了,接下來根據這個脈絡逐個閱讀對應組件的源碼,深層次學習各個組件。
源碼下載地址://download.csdn.net/download/cygodwg/11985475