`
cwqcwq
  • 浏览: 74858 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

打造自己的web容器(3)

    博客分类:
  • j2ee
阅读更多
---- 一个简单的servlet容器

上一篇讲到,我们的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调用成功:



第一个servlet容器的主要问题:
1、未实现servlet的生命周期
2、Response的getWriter()输出有问题
3、向上转换Request实例为javax.servlet.ServletRequest存在一定的安全性

在下一篇中,我将一一解决上述问题,且从下一篇开始,整体架构将以模块化组成。
  • 大小: 41.1 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics