Java Servlet(Java服务器小程序)是一个基于Java技术的Web组件,运行在服务器端,它由Servlet容器所管理,用于生成动态的内容。 Servlet是平台独立的Java类,编写一个Servlet,实际上就是按照Servlet规范编写一个Java类。Servlet被编译为平台独立 的字节码,可以被动态地加载到支持Java技术的Web服务器中运行。
简而言之:
在理解servlet执行过程和原理之前,先要弄清楚什么是web服务器,什么是servlet容器
1.Web服务器使用HTTP协议来传输数据。
最简单的一种情况是,用户在浏览器(客户端,client)中输入一个URL(如,www.programcreek.com/static.html),然后就能获取网页进行阅览。因此,服务器完成的工作就是发送网页至客户端。传输过程遵循HTTP协议,它指明了请求(request)消息和响应(response)消息的格式。Tomcat就是我们常用的web服务器之一
2.Servlet容器
Servlet容器的基本思想是在服务器端使用Java来动态生成网页。因此,Servlet容器是Web服务器和servlet进行交互的必不可少的组件,Servlet容器就是用来装Servlet的,我们可以把Tomcat理解一个web服务器中包含了ervlet容器,且servlet生命周期实例化、初始化、调用、销毁受控于Tomcat
3.Tomcat服务器是一个开源的servlet容器
Tomcat服务器接受客户请求并做出响应的过程如下:
使用方法:Servlet技术的核心是Servlet,用户在实现servlet时可以直接实现servlet或者间接实现它的实现类,一个servlet容器可以有多个servlet实现类以及与他相关的配置,public class DemoServlet1 extends HttpServlet
或 public class servletDemo01 implements Servlet
注意:每种servlet只能有一个实例,可以有多个servlet类,效率高,线程不安全
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
用servlet里的init() service()destory()来描述servlet生命周期会非常形象
1.被创建:
执行init()方法,只执行一次,引出问题:servlet什么时候被创建?
解决:第一次被访问时创建,也可以修改创建时机,如下图所示
2.提供服务:
执行service()方法
3.销毁:
执行destory()方法,只有在服务器正常关闭才会执行
Tomcat自动导入了servlet API,如图所示
共包含四个部分:
javax.servlet 其中包含定义servlet和servlet容器之间契约的类和接口。
javax.servlet.http 其中包含定义HTTP Servlet 和Servlet容器之间的关系。
javax.servlet.annotation 其中包含标注servlet,Filter,Listener的标注。它还为被标注元件定义元数据。
javax.servlet.descriptor,其中包含提供程序化登录Web应用程序的配置信息的类型。
罗列出最常用的servlet接口,全部位于javax.servlet包下,每个接口的使用方法请参考我的其他博客
当前环境使用的web服务器为Tomcat
用户通过单击某个链接或者直接在浏览器的地址栏中输入URL来访问web服务器,web服务器根据配置在xml中的信息去磁盘中加载对应的servlet实现类,并加载到servlet容器中,Tomcat根据http协议将用户输入的内容封装为request对象并转发到对应的servlet去实现,Tomcat将经过servlet的各种实现类处理过的信息(经过service()或doGet()doPost()方法处理)封装到response对象中,并经过http协议返回给用户所在的客户端
如图所示:
运行过程中的response和request对象是由Tomcat创建的,不需要用户自己创建
对于每一个应用程序,Servlet容器还会创建一个ServletContext对象。这个对象中封装了上下文(应用程序)的环境详情。每个应用程序只有一个ServletContext。每个Servlet对象也都有一个封装Servlet配置的ServletConfig对象,下面来介绍这些类
是servlet程序的配置信息类,由Tomcat创建,每个servlet创建时都会创建与之对应的ServletConfig,有三个作用
servletConfig.getServletName()
servletConfig.getIniteParameter("");
servletConfig.getServletContext();
ServletContext是一个接口,它表示servlet上下文对象,一个web工程只有一个servletContext对象实例,在将一个应用程序同时部署到多个容器的分布式环境中,每台Java虚拟机上的Web应用都会有一个ServletContext对象。是一个域对象,什么是域对象?
域对象:可以像map存储数据的对象,这里的域是指存储数据的操作范围
对象 | 存数据 | 取数据 | 删除数据 |
---|---|---|---|
Map | put() | get() | remove() |
域对象 | setAttribute() | getAttribute | removeAttribute() |
前面我们编写Servlet一直是通过实现Servlet接口来编写的,但是,使用这种方法,则必须要实现Servlet接口中定义的所有的方法,即使有一些方法中没有任何东西也要去实现,并且还需要自己手动的维护ServletConfig这个对象的引用。因此,这样去实现Servlet是比较麻烦的,GenericServlet抽象类的出现很好的解决了这个问题。本着尽可能使代码简洁的原则,GenericServlet实现了Servlet和ServletConfig接口,代码中出现了空实现方法
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.LocalStrings");
private transient ServletConfig config;
public GenericServlet() {
}
public void destroy() {
}
public String getInitParameter(String name) {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getInitParameter(name);
}
}
public Enumeration getInitParameterNames() {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getInitParameterNames();
}
}
public ServletConfig getServletConfig() {
return this.config;
}
public ServletContext getServletContext() {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getServletContext();
}
}
public String getServletInfo() {
return "";
}
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
public void log(String msg) {
this.getServletContext().log(this.getServletName() + ": " + msg);
}
public void log(String message, Throwable t) {
this.getServletContext().log(this.getServletName() + ": " + message, t);
}
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
public String getServletName() {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getServletName();
}
}
}
HttpServlet抽象类是继承于GenericServlet抽象类而来的。使用HttpServlet抽象类时,还需要借助分别代表Servlet请求和Servlet响应的HttpServletRequest和HttpServletResponse对象。
HttpServletRequest接口扩展于javax.servlet.ServletRequest接口,HttpServletResponse接口扩展于javax.servlet.servletResponse接口。
HttpServlet抽象类覆盖了GenericServlet抽象类中的Service( )方法
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
} catch (ClassCastException var6) {
throw new ServletException("non-HTTP request or response");
}
this.service(request, response);
}
调用了本类中的另一个service方法:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if (ifModifiedSince < lastModified) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
在service方法在解析HttpServletRequest中的方法参数,并调用以下方法之一:doGet,doPost,doHead,doPut,doTrace,doOptions和doDelete。这7种方法中,每一种方法都表示一个Http方法。doGet和doPost是最常用的。
参考:
https://blog.csdn.net/qq_19782019/article/details/80292110?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
附:servlet继承树图: