|
今天讲一下Servlet~~~
我们平时说的Servlet看上去很神秘,其实本质很简单,就是一个Java接口interface而已。
下面是javax.servlet的具体实现,只有几句代码:
public interface Servlet {
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}这个接口只有五个方法,而且看到这些方法的名字,大家也大概能猜出来这个方法是干什么的了。
这其中的service(ServletRequest req,ServletResponse res)方法,是Servlet的关键所在,是我们甚至可以说,其他方法”并不重要“,可以不进行实现。
这个方法的作用,是把Tomcat(Servlet容器)传入的请求进行处理,并让Tomcat知道向客户端发送怎样的回应。
那么客户端通过 Socket 传来的请求是如何变成ServletRequest类的呢?这就是容器 (如:Tomcat)的作用了,容器把客户端的消息解析,封装成ServletRequest,交给Servlet处理。
那么,问题就来了:
- Servlet容器怎么实现?HOW?
- 为什么要有Servlet?WHY?
我们举个例子来说明。
从原理上讲,Servlet可以处理任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器,所以我们就假设这样一个场景:
某大学大二学生的计算机网络实验课要求是自己实现一个HTTP服务器。
刘斌同学写了如下代码:
ServerSocket ss = new ServerSocket();//创建服务器
Socket socket = ss.accept();//监听客户端连接
/* 读取客户端数据
.............
*/
OutputStream soutput = socket.getOutputStream();
soutput.write(("HTTP/1.1 404 Not Found\r\n"+
"Content-Type: text/plain\r\n"+
"Content-length: 10\r\n\r\n"+
"Not Found\r\n").getBytes());
soutput.flush();总而言之,不管客户端发来什么消息,刘斌同学的服务器都告诉客户端:404 Not Found。(搞笑)
第二天,他发现,这样发送的消息是写死的,耦合性非常高,这并不是一个好事。
刘斌同学于是改写代码,抽象出一个Response类:
Response:
class Response{
private String res;
private OutputStream os;
public Response(OutputStream os){
this.os = os;
}
public void end(){
os.flush();
}
public OutputStream getOutputStream(){
return os;
}
}他是这样调用的:
/* 读取客户端数据
.............
*/
OutputStream soutput = socket.getOutputStream();
Response res = new Response(soutput);
OutputStream out = res.getOutputStream();
out.write(("HTTP/1.1 404 Not Found\r\n" +
"Content-Type: text/plain\r\n" +
"Content-length: 10\r\n\r\n" +
"Not Found").getBytes());
res.end();这样我们就给Response自己设置内容。
第三天,老师说,我给你们一个类,你们谁能最快把这个类放到你们代码中,完美运行,谁就能获得满分。
老师就给了一个叫TeacherServlet的类,这个类,是这么写的:
class TeacherServlet implements Servlet{
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
OutputStream out = res.getOutputStream();
out.write(("HTTP/1.1 404 Not Found\r\n" +
"Content-Type: text/plain\r\n" +
"Content-length: 10\r\n\r\n" +
"Not Found").getBytes());
}
@Override
public void init(ServletConfig config) throws ServletException {}
@Override
public ServletConfig getServletConfig() {return null;}
@Override
public String getServletInfo() {return null;}
@Override
public void destroy() {}
}刘斌一看,wc!简直是抄的我的代码,这太好改了啊!!
于是他这么写:
/* 读取客户端数据
.............
*/
OutputStream soutput = socket.getOutputStream();
Servlet servlet = new TeacherServlet();
ServletResponse res = new ServletResponse(soutput);
servlet.service(null, res);
res.end();可以看到,他把Response类重命名为了ServletResponse,老师的代码只是给他原来的代码多了一层封装,他交的最快,所以他得了满分。
那么这里,刘斌同学写的这些代码,就叫一个“Servlet容器”。
那么两个问题中的一个,即Servlet容器怎么实现的问题,就解决了,
tomcat虽然比这个复杂的多,但是原理真的是和刘斌同学的代码是一样的,就是一个回调(callback)。
但是,这可远远不是一个符合标准的Servlet容器。
首先,他的ServletResponse缺少很多必要的方法;其次,他看到老师没有调用ServletRequest的方法, 就把req的值传为null,这可是真的非常投机取巧了。
其实这个故事里,刘斌的老师其实是程序员的作用,老师可以开发Servlet,来给用户使用。
而刘斌写的程序相当于Tomcat,Jetty……
这些Servlet容器的代码虽然不同,但是他们都完整的实现了Servlet标准,也就是说,老师可以不管他们的代码,写的类可以在他们的容器中完美运行。
到这里第二个问题也解决了,Servlet的作用就是:
为java程序提供一个统一的web应用的规范。
我希望读完这篇文章,当别人,比如面试官问起你知道Servlet么?
你可以自信滴讲,唉,知道,就是一个interface而已嘛~
<hr/>有看不懂的地方,欢迎评论留言哟~~~
欢迎点赞,欢迎评论,欢迎关注,欢迎赞赏,欢迎欢迎~~~ |
|