[b][color=red]---- 一个简单的servlet容器[/color][/b]
上一篇讲到,我们的web容器已经可以读取静态资源,在这一篇中,我将建立一个简单的servlet容器,之所以简单,是因为有它的局限性,在后面我会总结,余下的问题我将在下一篇中一一解决。
本篇的第一个servlet容器主要完成如下功能:
* 等待HTTP请求。
* 构造一个ServletRequest对象和一个ServletResponse对象。
* 假如该请求需要一个静态资源的话,调用StaticResourceProcessor实例的process方法,同时传递ServletRequest和ServletResponse对象。
* 假如该请求需要一个servlet的话,加载servlet类并调用servlet的service方法,同时传递ServletRequest和ServletResponse对象。
注意:在这个servlet容器中,每一次servlet被请求的时候,servlet类都会被加载。
第一个servlet容器由以下类组成:
* HttpServer:容器的启动类,
* Request:实现了ServletRequest
* Response:实现了ServletResponse
* IProcessor:处理器接口,后期会演变为连接器
* StaticResourceProcessor:处理静态资源
* ServletProcessor:处理servlet调用
* MyClassLoader:继承自ClassLoader,用于加载class
* Constants:常量
上一篇已经对部分代码作了解释,接下来,我会对新增的代码作解释。
HttpServer类:
Response类:
Request类:
ServletProcessor类:
StaticResourceProcessor类:
Constants类:
MyClassLoader类:
测试servlet:MyPrimitiveServlet
运行HttpServer,启动容器测试:
在浏览器中键入:http://localhost:8080/servlet/MyPrimitiveServlet
出现如下界面,则表明servlet调用成功:
[img]/upload/attachment/121980/cefbdbc2-d9b2-379d-a642-ff12133f1753.jpg[/img]
第一个servlet容器的主要问题:
1、未实现servlet的生命周期
2、Response的getWriter()输出有问题
3、向上转换Request实例为javax.servlet.ServletRequest存在一定的安全性
在下一篇中,我将一一解决上述问题,且从下一篇开始,整体架构将以模块化组成。
上一篇讲到,我们的web容器已经可以读取静态资源,在这一篇中,我将建立一个简单的servlet容器,之所以简单,是因为有它的局限性,在后面我会总结,余下的问题我将在下一篇中一一解决。
本篇的第一个servlet容器主要完成如下功能:
* 等待HTTP请求。
* 构造一个ServletRequest对象和一个ServletResponse对象。
* 假如该请求需要一个静态资源的话,调用StaticResourceProcessor实例的process方法,同时传递ServletRequest和ServletResponse对象。
* 假如该请求需要一个servlet的话,加载servlet类并调用servlet的service方法,同时传递ServletRequest和ServletResponse对象。
注意:在这个servlet容器中,每一次servlet被请求的时候,servlet类都会被加载。
第一个servlet容器由以下类组成:
* HttpServer:容器的启动类,
* Request:实现了ServletRequest
* Response:实现了ServletResponse
* IProcessor:处理器接口,后期会演变为连接器
* StaticResourceProcessor:处理静态资源
* ServletProcessor:处理servlet调用
* MyClassLoader:继承自ClassLoader,用于加载class
* Constants:常量
上一篇已经对部分代码作了解释,接下来,我会对新增的代码作解释。
HttpServer类:
// create Response object
Response response = new Response(output);
response.setRequest(request);
if (request.getUri().startsWith("/servlet/")) { //暂时的实现,如果路径以 /servlet/ 开头则认为是调用servlet
IProcessor processor = new ServletProcessor();
processor.process(request, response);
}
else {
IProcessor processor = new StaticResourceProcessor();
processor.process(request, response);
}
// Close the socket
socket.close();
Response类:
public class Response implements ServletResponse {
//...省略ServletResponse的方法实现
public PrintWriter getWriter() throws IOException {
// autoflush is true, println() will flush,
// but print() will not.
writer = new PrintWriter(output, true);
return writer;
}
}
Request类:
public class Request implements ServletRequest {
//...省略ServletRequest的方法实现
//其余方法与上一篇一致
}
ServletProcessor类:
public class ServletProcessor implements IProcessor {
public void process(Request request, Response response) throws ServletException {
String uri = request.getUri();
String servletName = uri.substring(uri.lastIndexOf("/") + 1);
ClassLoader loader = new MyClassLoader(this.getClass().getClassLoader());
Class< ? > servletClass = null;
try {
servletClass = loader.loadClass(servletName);//加载class
}
catch (ClassNotFoundException e) {
throw new ServletException(e);
}
Servlet servlet = null;
if (null != servletClass) {
try {
servlet = (Servlet) servletClass.newInstance();
servlet.service(request, response);
}
catch (Exception e) {
throw new ServletException(e);
}
}
}
}
StaticResourceProcessor类:
public class StaticResourceProcessor implements IProcessor {
public void process(Request request, Response response) throws ServletException, IOException {
response.sendStaticResource();//直接读取资源
}
}
Constants类:
public class Constants {
/* WEB容器的根目录 */
public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "WebContent";
/* class的根路径 */
public static final String CLASS_PATH = WEB_ROOT + File.separator + "WEB-INF" + File.separator + "classes";
}
MyClassLoader类:
public class MyClassLoader extends ClassLoader {
private String classPath = null;
protected MyClassLoader(ClassLoader parent) {
super(parent);
init();
}
private void init() {
classPath = Constants.CLASS_PATH;
}
/*
* 此方法应该被类加载器的实现重写,该实现按照委托模型来加载类
* @see java.lang.ClassLoader#findClass(java.lang.String)
*/
protected Class< ? > findClass(String className) throws ClassNotFoundException {
String classFileName = className.replace('.', '/') + ".class";
URL url = findResource(classFileName);
byte[] bytes = null;
if (null == url) {
throw new ClassNotFoundException("Can't find [" + className + "]");
}
else {
InputStream input = null;
try {
input = url.openStream();
if (input == null) {
throw new ClassNotFoundException("Can't load [" + className + "]");
}
else {
ByteArrayOutputStream baos = new ByteArrayOutputStream(10240);
byte[] buf = new byte[1024];
int bytesRead = 0;
while (bytesRead >= 0) {
baos.write(buf, 0, bytesRead);
bytesRead = input.read(buf);
}
bytes = baos.toByteArray();
}
}
catch (IOException e) {
throw new ClassNotFoundException(className, e);
}
finally {
try {
input.close();
}
catch (IOException ingore) {
}
}
}
Class< ? > theClass = defineClass(className, bytes, 0, bytes.length);
if (theClass == null)
throw new ClassFormatError();
return theClass;
}
/*
* 查找具有给定名称的资源。类加载器实现应该重写此方法,以指定从何处查找资源
* @see java.lang.ClassLoader#findResource(java.lang.String)
*/
protected URL findResource(String name) {
try {
URL url = super.findResource(name);
if (null != url) {
return url;
}
File path = new File(classPath);
if (path.isDirectory()) {
String pathRoot = path.getCanonicalPath();
StringBuffer sb = new StringBuffer(pathRoot);
sb.append(File.separator).append(name);
File resourceFile = new File(sb.toString());
if (resourceFile.exists()) {
System.out.println("Resource [" + name + "] was found, in [" + pathRoot + "]");
url = new URL("file:///" + resourceFile.getCanonicalPath());
}
}
if (null == url) {
return null;
}
else {
return url;
}
}
catch (IOException ex) {
return null;
}
}
}
测试servlet:MyPrimitiveServlet
public class MyPrimitiveServlet implements Servlet {
public void destroy() {}
public ServletConfig getServletConfig() {}
public String getServletInfo() {}
public void init(ServletConfig arg0) throws ServletException {}
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
System.out.println("from service");
PrintWriter out = response.getWriter();
out.println("Hello. MyServletContainer!");
out.print("Violets are blue.");
}
}
运行HttpServer,启动容器测试:
在浏览器中键入:http://localhost:8080/servlet/MyPrimitiveServlet
出现如下界面,则表明servlet调用成功:
[img]/upload/attachment/121980/cefbdbc2-d9b2-379d-a642-ff12133f1753.jpg[/img]
第一个servlet容器的主要问题:
1、未实现servlet的生命周期
2、Response的getWriter()输出有问题
3、向上转换Request实例为javax.servlet.ServletRequest存在一定的安全性
在下一篇中,我将一一解决上述问题,且从下一篇开始,整体架构将以模块化组成。