打造自己的web容器(3)

[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类:

// 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存在一定的安全性

在下一篇中,我将一一解决上述问题,且从下一篇开始,整体架构将以模块化组成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值