自己写一个简单的servlet,能够跑一个简单的servlet,说明一下逻辑。
首先是写一个简单的servlet,这就关联到javax.servlet和javax.servlet.http这两个包的类,其中一个比较重要的接口就是:javax.servlet.Servlet,所有的servlet必须实现实现或者继承实现该接口的类。 Servlet接口有五个方法:
在Servlet的五个方法中,init,service和destroy是servlet的生命周期方法。在servlet类已经初始化之后,init方法将会被servlet容器所调用。servlet容器只调用一次,以此表明servlet已经被加载进服务中。init方法必须在servlet可以接受任何请求之前成功运行完毕。一个servlet程序员可以通过覆盖这个方法来写那些仅仅只要运行一次的初始化代码,例如加载数据库驱动,值初始化等等。在其他情况下,这个方法通常是留空的。
servlet容器为servlet请求调用它的service方法。servlet容器传递一个javax.servlet.ServletRequest对象和javax.servlet.ServletResponse对象。ServletRequest对象包括客户端的HTTP请求信息,而ServletResponse对象封装servlet的响应。
在servlet的生命周期中,service方法将会给调用多次。 当从服务中移除一个servlet实例的时候,servlet容器调用destroy方法。这通常发生在servlet容器正在被关闭或者servlet容器需要一些空闲内存的时候。仅仅在所有servlet线程的service方法已经退出或者超时淘汰的时候,这个方法才被调用。在servlet容器已经调用完destroy方法之后,在同一个servlet里边将不会再调用service方法。destroy方法提供了一个机会来清理任何已经被占用的资源,例如内存,文件句柄和线程,并确保任何持久化状态和servlet的内存当前状态是同步的。
我们可以写一个比较简单的servlet:
现在,让我们从一个servlet容器的角度来研究一下servlet编程。总的来说,一个全功能的servlet容器会为servlet的每个HTTP请求做下面一些工作:
1.当第一次调用servlet的时候,加载该servlet类并调用servlet的init方法(仅仅一次)。
2. 对每次请求,构造一个javax.servlet.ServletRequest实例和一个javax.servlet.ServletResponse实例。
3.调用servlet的service方法,同时传递ServletRequest和ServletResponse对象。
4.当servlet类被关闭的时候,调用servlet的destroy方法并卸载servlet类。
我们的第一个servlet容器不是全功能的。因此,她非常简单的servlet,而且也不调用servlet的init方法和destroy方法。相反它做了下面的事情:
1. 等待HTTP请求。
2. 构造一个ServletRequest对象和一个ServletResponse对象。
3. 假如该请求需要一个静态资源的话,调用StaticResourceProcessor实例的process方法,同时传递ServletRequest和ServletResponse对象。
4. 假如该请求需要一个servlet的话,加载servlet类并调用servlet的service方法,同时传递ServletRequest和ServletResponse对象。
所以我们的第一个简单的servlet容器是:
其中的ServletProcessor1 的代码是:
使用的Response 和 Request 关键的代码,如下面所示,基本上和上一篇里面的Response 和 Request 没有太大的区别,其中常量Constants.WEB_ROOT = “D:/webroot/”,这个地址是我充当服务器返回数据存储的地址,具体的代码见附件。
Request 中比较重要的代码如下,具体的代码见附件
测试的路径是:http://127.0.0.1:12345/servlet/PrimitiveServlet
需要把编译好的class文件放到D:/webroot/(这个是我的数据存储的地方)
结果是:
在看看我们的servlet容器,还是有很多地方可以优化的,例如在加载servlet,传入参数处理的过程中:
Servlet servlet = null;
try {
servlet = (Servlet) myClass.newInstance();
servlet.service((ServletRequest) request, (ServletResponse) response);
}
这会危害安全性。知道这个servlet容器的内部运作的Servlet程序员可以分别把ServletRequest和ServletResponse实例向下转换为ex02.pyrmont.Request和ex02.pyrmont.Response,并调用他们的公共方法。拥有一个Request实例,它们就可以调用parse方法。拥有一个Response实例,就可以调用sendStaticResource方法。 你不可以把parse和sendStaticResource方法设置为私有的,因为它们将会被其他的类调用。不过,这两个方法是在个servlet内部是不可见的。其中一个解决办法就是让Request和Response类拥有默认访问修饰,另外比较推荐的一种方法,就是增加一个类:
public class RequestFacade implements ServletRequest
public Class ResponseFacade implements ServletRequest
这样的代码相应的变化为:
Servlet servlet = null;
RequestFacade requestFacade = new RequestFacade(request);
ResponseFacade responseFacade = new ResponseFacade(response);
try {
servlet = (Servlet) myClass.newInstance();
servlet.service((ServletRequest) requestFacade, (ServletResponse) responseFacade);
}
ok,到这里我们的一个简单的servlet容器,已经完成了,还是比较的简单的。
附件:源代码