博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Servlet Java
阅读量:2207 次
发布时间:2019-05-04

本文共 8981 字,大约阅读时间需要 29 分钟。

一:什么是Servlet

Servlet 说白了就是个类,是个接口

然后它的作用是处理服务器接收到的请求

在Servlet4.0的中是这么描述的:

A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web clients, usually across HTTP, the HyperText Transfer Protocol.


版本说明:Servlet4.0、Tomcat9.0

我们通常创建的Servlet 是这样的

public class XXX extends HttpServlet

继承了HttpServlet这个抽象类

在这个抽象类里,就有我们熟悉的doGet()、doPost()等方法

也正是因为这个继承关系,我们则可以重写doGet()、doPost()他们

由此来处理服务器收到的请求

而在HttpServlet之上,还有一个抽象类—GenericServlet

public abstract class HttpServlet extends GenericServlet
public abstract class GenericServletextends java.lang.Objectimplements Servlet, ServletConfig, java.io.Serializable

1.GenericServlet 了实现Servlet接口的init()、destroy()、service()等方法

init()方法其实没那么神秘

在GenericServlet中有两个init(),一个代参,一个不带参

代参:

public void init(ServletConfig config) throws ServletException {
this.config = config; this.init(); }

不带参:

public void init() throws ServletException {
// NOOP by default }

真的没了,就是这样

除了代参的那个方法做了一下赋值

一样的,destroy()也是

public void destroy() {
// NOOP by default }

就是空的

init()和destroy()会由Servlet的容器调用

你倒是可以在这里面做一个log一些信息

而service()方法在GenericServlet 中就是个抽象方法,啥代码逻辑都没有

public abstract void service(ServletRequest req, ServletResponse res)            throws ServletException, IOException;

处理请求,还得看HttpServlet

它的service()方法就是处理请求的主战场了

protected void service(HttpServletRequest req, HttpServletResponse resp)        throws ServletException, IOException {
String method = req.getMethod(); if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req); if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason // to go through further expensive logic doGet(req, resp); } else {
long ifModifiedSince; try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); } catch (IllegalArgumentException iae) {
// Invalid date header - proceed as if none was set ifModifiedSince = -1; } if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified); doGet(req, resp); } else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) {
doPost(req, resp); } else if (method.equals(METHOD_PUT)) {
doPut(req, resp); } else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp); } else {
// // Note that this means NO servlet supports whatever // method was requested, anywhere on this server. // String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } }

当有请求时,这个方法会由Servlet的容器调用

然后service()里面又会调用doGet()方法

2.GenericServlet 实现了ServletConfig接口的getServletContext()、getServletName()等方法

(这个不是特别重要,具体我就不展开了)

3.GenericServlet 实现了java.io.Serializable接口

这个接口是一个marker interface

其中并不含什么方法

其作用是标记这个类是Serializable

而Serializable的意思就是:

这个对象可以转化成字节序列

可以借助 ObjectOutputStream写入到一个文件里,又可以用ObjectInputStream再读出来

照应主题,其实只要一个类实现了Servlet接口,那么就可以说他是一个Servlet了

除此之外,你也可以选择继承已经实现Servlet接口的类

例如上面提到的GenericServlet 和HttpServlet

继承过后,又是一个Servlet~


二:Servlet的配置

Servlet写好了,直接把他放到webapps下就可以了吗?

当然不行。。

这里面多少还是有些讲究的

这里以Tomcat为例

Tomcat对应用的部署有一定的要求

目录结构就是其中之一

在这里插入图片描述

我们写好的Servlet应该被编译成.class文件,然后根据packages的关系,放到WEB-INF/classes下

其中的编译工作,Tomcat不会帮我们做

大家其实也可以看到,目录结构中并没有哪个地方可以放我们写出来的.java文件

一个方法是我们手动用 javac+所需的jar包进行编译出.class文件

javac -classpath servlet-api.jar MyTestServlet.java

注 意 , 编 译 S e r v l e t 是 需 要 额 外 的 j a r 包 的 \color{blue}{注意,编译Servlet是需要额外的jar包的} Servletjar

而且,不同的服务器需要的jar包也可能不同

Tomcat需要的是servlet-api.jar

而对于Glassfish和JBoss则需要javaee.jar

第二个方法就是借助像Eclipse这样的IDE帮我们了

相信大家都是利用IDE进行开发的

IDE可以帮我们完成很多工作,包括java文件编译和构建上面所说的目录结构

IDE会帮我们把编译出来的.class文件放到WEB-INF/classes下正确的位置


访 问 S e r v l e t \color{blue}{访问Servlet} 访Servlet

除了编译Servlet外,我们还差一步就可以完成Servlet的部署了

那就是告诉服务器知道,哪些.class文件是Servlet

一种方法是在web.xml文件中声明

sonoojaiswal
DemoServlet

然后,web.xml还允许我们做映射

sonoojaiswal
/welcome

我们可以通过一些通配符来将好多不同的url映射到一个Servlet上

sonoojaiswal
/*.map

上面这个url-pattern 可以理解为映射的规则

/*.map的意思就是在/目录下,所有后缀为.map的请求都会被对应到名为sonoojaiswal的Servlet

举例:

http://localhost:8080/EElearn/1.map

http://localhost:8080/EElearn/2.map
http://localhost:8080/EElearn/abc.map

上面三个URL会对应到同一个Servlet----sonoojaiswal

注 意 , w e b . x m l 中 说 的 / 目 录 指 的 是 当 前 应 用 的 根 目 录 \color{blue}{注意,web.xml中说的/目录指的是当前应用的根目录} web.xml/

回到前面那个关于目录结构的图

/目录就是对应web-app/

对应上面的例子就是EElearn/

要与之区分对是另外一个/目录

假设在一个超链接中

go

注意,上面这个链接是无法正确访问Servlet的

原因是这里的/目录对应的是服务器的根目录

也就是 http://localhost:8080/

所以正确的超链接应该为:

go

希望大家一定要区分清楚,不然这一个矮凳子会让你找Bug找到崩溃

除了通过web.xml声明,还可以利用注解

@WebServlet("/FirstServlet")public class xxx extends HttpServlet

即声明了这个是名为FirstServlet的Servlet

注解当然也可以设置映射

@WebServlet(name="TestServlet", urlPatterns={
"/path", "/alt"})

三:Servlet生命周期

我们自己写的Servlet默认是,有请求访问时才开始加载的

然后,我们也可以通过web.xml的配置来让Servlet预先加载

<load-on-startup>标签放到<servlet>标签下

sonoojaiswal
DemoServlet
0

标签之间可以放入整数

负数表示不会预加载这个Servlet

大于或等于0的整数则是按自然数顺序加载


S e r v l e t 的 创 建 \color{blue}{Servlet的创建} Servlet

接下来细讲

版本说明:Servlet4.0 Tomcat9.0

这里从Tomcat启动开始讲起

org.apache.catalina.core.StandardContext会实现org.apache.catalina.Context接口

这个接口相当于javax.servlet.Servlet接口中的ServletContext

可能听着会有点迷糊。。我再解释解释

在Servlet4.0的标准中有一个接口叫ServletContext

这个接口的描述是这样的

Defines a set of methods that a servlet uses to communicate with its servlet container

而Tomcat选择用它自己的org.apache.catalina.Context接口去代替ServletContext接口

public interface Contextextends Container, ContextBind

A Context is a Container that represents a servlet context

而StandardContext则是对Tomcat的Context接口的实现

好的,接下来继续

ServletContext或根据web.xml和注解中的配置信息(例如:@WebServlet("/xx"))

来统一管理其中的servlet、filter、listener

然后,对于servlet

在org.apache.catalina下有一个Wrapper接口

这个接口可以用来管理Servlet的生命周期的

Tomcat的API文档有这么一段描述

Implementations of Wrapper are responsible for managing the servlet life cycle for their underlying servlet class, including calling init() and destroy() at appropriate times, as well as respecting the existence of the SingleThreadModel declaration on the servlet class itself.

然后,StandardWrapper是Wrapper接口的一个实现

public class StandardWrapperextends ContainerBaseimplements ServletConfig, Wrapper, NotificationEmitter

实际上Servlet的加载和初始化是由这个类调用其load()方法实现的

(具体load()的代码我这就不全部展开了,大家有兴趣可以自行看看源码)

简单的说,就是Servlet的实例化:

servlet = (Servlet) instanceManager.newInstance(servletClass);

其中的servletClass:

protected String servletClass = null;

是一个字符串,也就是我们web.xml中配置的<servlet-class>标签中的内容

(包含了package的class name,如:com.test.Servlet1,即为Servlet1的servletClass)

而我们自己写的Servlet中的init()

只是在StandardWrapper完成Servlet的加载和初始化后才调用的

需要补充的是,servlets 和 filters 是会被加载进内存,并被所有的请求共享

我在这其实踩了坑。。。

看源码的时候,看到有一个StandardWrapper中有一个instancePool

然后看着看着觉得很奇怪,卡了很久

后来才知道,这个东西在Servlet2.4的时候就被弃用了

javax.servlet

Interface SingleThreadModel
Deprecated.
As of Java Servlet API 2.4, with no direct replacement.

为啥弃用了,源码里还有(小声bb,哭了)


S e r v l e t 的 业 务 处 理 \color{blue}{Servlet的业务处理} Servlet

即service()

当服务器收到请求后,会创建新的 HttpServletRequest and HttpServletResponse 对象

(注意,是新的对象)

然后把他们传到FilterChain,执行一些列doFilter()后

到Servlet实例,执行service()方法

FilterChain是Servlet4.0中的接口

在Tomcat中,由ApplicationFilterChain来实现FilterChain接口


S e r v l e t 生 命 周 期 的 结 束 \color{blue}{Servlet生命周期的结束} Servlet

别被destroy()给骗了

这个方法和init()一样,实际上没有代码逻辑的

真正处理Servlet的仍然是StandardWrapper

当关闭Tomcat时,才会对Servlet进行销毁

StandardWrapper调用unload()来结束一个Servlet

下面是大概的流程:

...instance.destroy();...instance = null;...

(instance就是一个Servlet的实例)


This is done so that as a server side developer you can focus on what to do with the HTTP request and responses and not bother about dealing with code that deals with networking etc. The container will take care of things like wrapping the whole thing in a HTTP response object and send it over to the client (say a browser).

转载地址:http://uliyb.baihongyu.com/

你可能感兴趣的文章
HTML中表格的使用
查看>>
(模板 重要)Tarjan算法解决LCA问题(PAT 1151 LCA in a Binary Tree)
查看>>
(PAT 1154) Vertex Coloring (图的广度优先遍历)
查看>>
(PAT 1115) Counting Nodes in a BST (二叉查找树-统计指定层元素个数)
查看>>
(PAT 1143) Lowest Common Ancestor (二叉查找树的LCA)
查看>>
(PAT 1061) Dating (字符串处理)
查看>>
(PAT 1118) Birds in Forest (并查集)
查看>>
数据结构 拓扑排序
查看>>
(PAT 1040) Longest Symmetric String (DP-最长回文子串)
查看>>
(PAT 1145) Hashing - Average Search Time (哈希表冲突处理)
查看>>
(1129) Recommendation System 排序
查看>>
PAT1090 Highest Price in Supply Chain 树DFS
查看>>
(PAT 1096) Consecutive Factors (质因子分解)
查看>>
(PAT 1019) General Palindromic Number (进制转换)
查看>>
(PAT 1073) Scientific Notation (字符串模拟题)
查看>>
(PAT 1080) Graduate Admission (排序)
查看>>
Play on Words UVA - 10129 (欧拉路径)
查看>>
mininet+floodlight搭建sdn环境并创建简答topo
查看>>
【linux】nohup和&的作用
查看>>
Set、WeakSet、Map以及WeakMap结构基本知识点
查看>>