深入学习Tomcat——servlet容器
上一篇文章里分析了一个简单的Web容器的实现过程,今天笔者来分析一个servlet容器是如何实现的。相信通过这两篇博客读者就可以理解为什么说Tomcat是一个容器了,既是Web容器又是servlet容器。所谓Web容器仅仅是可以处理静态资源(html)但是servlet就不一样了,由于在servlet里面我们可以按照servlet的规范编写我们的逻辑所以就出现了变化无穷的网页。所谓的Web2.0正
上一篇文章里分析了一个简单的Web容器的实现过程,今天笔者来分析一个servlet容器是如何实现的。相信通过这两篇博客读者就可以理解为什么说Tomcat是一个容器了,既是Web容器又是servlet容器。所谓Web容器仅仅是可以处理静态资源(html)但是servlet就不一样了,由于在servlet里面我们可以按照servlet的规范编写我们的逻辑所以就出现了变化无穷的网页。所谓的Web2.0正是基于这种动态的网页技术来实现的,互联网发展到今天每个阵营拥有自己的一套成熟处理方式,微软用的是asp,java用的是servlet、jsp技术。其实大同小异,都是将逻辑放在服务器中,然后动态的生成html,进而将生成的html传输到客户端,最终这些html代码被浏览器解析最终呈现出色彩斑斓的网页。
说远了,接着回来说咱的servlet容器。
相信绝大多数读者都写过servlet类,所有的Servlet程序都需要实现javax.servlet.servlet接口。(关于servlet接口在这里就不赘述了,我们需要了解的是servlet的5个方法当中init(),service()和destroy()方法分别是在servlet的哪个生命周期调用的。)
首先看HttpServer2当中的核心代码,和上一篇介绍Web容器的中的HttpServer代码类似都是等待一个请求然后创建Request和Response对象。不同的是这里进行判断是请求静态资源还是请求一个Servlet。
if (request.getUri().startsWith("/servlet/")) {
ServletProcessor2 processor = new ServletProcessor2();
processor.process(request, response);
} else {
StaticResourceProcessor processor = new StaticResourceProcessor();
processor.process(request, response);
}
如果客户端请求的是servlet,那么交给Processor进行处理。在处理请求的过程中Servlet容器和Web容器不同的是:后者仅仅是将静态的资源通过输出流输出到客户端,而前者需要加载servlet这个类进而按照JavaEE的规范执行servlet的service方法。所以在Processor类当中需要请求的URL加载Servlet的类。
String uri = request.getUri();
String servletName = uri.substring(uri.lastIndexOf("/") + 1);
URLClassLoader loader = null;
try {
// create a URLClassLoader
URL[] urls = new URL[1];
URLStreamHandler streamHandler = null;
File classPath = new File(Constants.WEB_ROOT);
// the forming of repository is taken from the createClassLoader method in
// org.apache.catalina.startup.ClassLoaderFactory
String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString();
// the code for forming the URL is taken from the addRepository method in
// org.apache.catalina.loader.StandardClassLoader class.
urls[0] = new URL(null, repository, streamHandler);
loader = new URLClassLoader(urls);
} catch (IOException e) {
System.out.println(e.toString());
}
Class myClass = null;
try {
myClass = loader.loadClass(servletName);
} catch (ClassNotFoundException e) {
System.out.println(e.toString());
}
如果找不到所请求的servlet那么会抛出ClassNotFoundException,如果找到所请求的Servlet并且load成功那么下面要做的就是执行其service方法了。
Servlet servlet = null;
RequestFacade requestFacade = new RequestFacade(request);
ResponseFacade responseFacade = new ResponseFacade(response);
try {
servlet = (Servlet) myClass.newInstance();
servlet.service((ServletRequest) requestFacade, (ServletResponse) responseFacade);
} catch (Exception e) {
System.out.println(e.toString());
} catch (Throwable e) {
System.out.println(e.toString());
}
在这里Tomcat使用了facade patterns(外观模式?门面模式?) 这样做的好处是:开发人员只能拿到“假”的Response和Request类,从而避免了Request和Response两个类中的类似parse()、sendStaticResource()等共有方法被误用。RequestFacade类如下ResponseFacade类大同小异。
public class RequestFacade implements ServletRequest {
private ServletRequest request = null;
public RequestFacade(Request request) {
this.request = request;
}
/* implementation of the ServletRequest*/
public Object getAttribute(String attribute) {
return request.getAttribute(attribute);
}
public Enumeration getAttributeNames() {
return request.getAttributeNames();
}
public String getRealPath(String path) {
return request.getRealPath(path);
}
public RequestDispatcher getRequestDispatcher(String path) {
return request.getRequestDispatcher(path);
}
public boolean isSecure() {
return request.isSecure();
}
public String getCharacterEncoding() {
return request.getCharacterEncoding();
}
public int getContentLength() {
return request.getContentLength();
}
public String getContentType() {
return request.getContentType();
}
public ServletInputStream getInputStream() throws IOException {
return request.getInputStream();
}
public Locale getLocale() {
return request.getLocale();
}
public Enumeration getLocales() {
return request.getLocales();
}
public String getParameter(String name) {
return request.getParameter(name);
}
public Map getParameterMap() {
return request.getParameterMap();
}
public Enumeration getParameterNames() {
return request.getParameterNames();
}
public String[] getParameterValues(String parameter) {
return request.getParameterValues(parameter);
}
public String getProtocol() {
return request.getProtocol();
}
public BufferedReader getReader() throws IOException {
return request.getReader();
}
public String getRemoteAddr() {
return request.getRemoteAddr();
}
public String getRemoteHost() {
return request.getRemoteHost();
}
public String getScheme() {
return request.getScheme();
}
public String getServerName() {
return request.getServerName();
}
public int getServerPort() {
return request.getServerPort();
}
public void removeAttribute(String attribute) {
request.removeAttribute(attribute);
}
public void setAttribute(String key, Object value) {
request.setAttribute(key, value);
}
public void setCharacterEncoding(String encoding)
throws UnsupportedEncodingException {
request.setCharacterEncoding(encoding);
}
}
(文中涉及到的代码可以在这里找到,参考资料《How Tomcat Works》)
更多推荐
所有评论(0)