四个小问题,简单解释一下 tomcat 和servlet 的关系

1. Servlet 是什么?

servlet 是个 sun 公司开发的一种web技术,这个技术制定了一个规范,落到代码上他就是一个接口。那这个规范是做什么用的呢?这个规范是处理网络请求用的,所以,实现了这个规范的类是用来处理网络请求的。

// Servlet.java 是源码,在官方 jar 包里。
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();
}

在概念上,狭义的 servlet 是指 java 语言实现的一个接口,广义的 servlet 是指任何实现这个接口的类,一般情况下,人们将 servlet 理解为后者,所以下面提到的 servlet 均是指实现 servlet 接口的类,这个类是谁开发的?是程序员们开发的。开发的这个类是干什么用的?是为了处理(浏览器的)请求用的。

// GenericServlet.java 是源码,在官方的 jar 包里。
public abstract class GenericServlet 
    implements Servlet, ServletConfig, java.io.Serializable{
     }

// HttpServlet.java 是源码,在官方的 jar 包里。
public abstract class HttpServlet extends GenericServlet{
     }

程序员自己开发的 servlet,都是从 extend HttpServlet 开始。然后通过重写父类方法,实现自己的业务逻辑。
NOTE:CookieTest 是程序员自定义的类,但它现在也叫 servlet。

public class CookieTest extends HttpServlet {
     

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
     
        response.setContentType("text/html");
        String name = request.getParameter("username");
        Cookie cookie = new Cookie("username", name);
        cookie.setMaxAge(30 * 60);
        response.addCookie(cookie);

        RequestDispatcher view = request.getRequestDispatcher("cookieresult.jsp");
        view.forward(request, response);
    }
}

2. 那 tomcat 是干什么的?

继续看 CookieTest,这个类里是程序员自己写的逻辑,它从浏览里的请求里拿出了 username 参数,接着创建了一个 cookie,最后把 cookie 返回给浏览器。

上面的代码是处理浏览器请求的,请问,谁监听端口?谁接收请求?谁把处理结果返回给浏览器?

如果只有这个 CookieTest servlet,那是做不了 web 服务的。因为 servlet 还缺一个与浏览器进行 http 通信的“模块”。

怎么办?
有两种办法:

  • (1)程序源自己再开发一段程序,监听端口、接收浏览器的请求并把它转交给 servlet、最后再从 servlet 拿到处理结果并将结果返回给浏览器。(这只是最基本的功能要求)
  • (2)程序员不自己开发,找一个已有的、成熟的、稳定的、被广泛使用的、具有与(1)中相同功能甚至功能更强大的程序。

那(2)中描述的程序有吗?
有:Tomcat 就是其中之一,Apache 开发的程序并且开源。它能监听端口,接收请求并转发给 servlet、从servlet 拿处理结果并返回给浏览器。其他功能在此不做赘述。

3. Tomcat 是程序?是 servlet 容器?

tomcat 是个具有 HTTP 通信功能的程序,同时也经常看到好多博客中有写 “tomcat 是个 servlet 容器”。

为什么会叫它 “容器” 呢?

这里的 “容器” 跟 docker 攀不上亲戚。
之所以叫它“容器”,是因为要想让 tomcat 把请求转发给 servlet,并从 servlet 拿回处理结果,就必须把 servlet 所在的整个项目文件放到 tomcat 的 webapps目录下。

$ ls apache-tomcat-9.0.40

BUILDING.txt    LICENSE         README.md       RUNNING.txt     conf            logs            webapps
CONTRIBUTING.md NOTICE          RELEASE-NOTES   bin             lib             temp            work

在实际应用中,webapps 目录下,可不止一个项目,每个项目里也不只一个 servlet,tomcat 负责给这些 servlet 做 HTTP 通信“接口”。tomcat 就像 “容器” 一样,里面承载了好多个 servlet。所以,tomcat 即是程序,也是“容器”。(这里只是拿请求转发作为例子,tomcat 干的事可不止这么一件的!)

4. tomcat 怎么将请求精确转发给 servlet ?

一个 tomcat 下有好多个 servlet,那 tomcat 是怎么请求精确转发给 servlet 的呢?
tomcat 根据 URL 先确定转发给 webapps 下的哪个项目,再确定转发给项目中的哪个 servlet。

URL:http://localhost:8080/ch06-cookies/checkcookie.do
通信协议:http://(使用 http 通信协议)。
服务器IP:localhost (本地)。
端口号:8080 (tomcat 对应的 socket 的端口号默认是8080,大家常说的 tomcat “监听” 8080 端口)。
uri:/ch06-cookies/checkcookie.do (tomcat 用这部分判断是要将请求转发给哪个 servlet)。

  • webapps 下的项目名字:ch06-cookies
  • 项目中的 servlet:checkcookie.do

在 tomcat 的 webapps 目录下,存放的项目文件结构是有要求的。
(1)webapps 目录下,每一个文件夹就是一个单独的 web 项目,文件夹的名字会作为 uri 的起始。

# 这里有两个项目
$ ls webapps
ch06-cookies  helloservlet

确定了项目,接下来就是确定请求该转发给哪个 servlet 。
ch06-cookies 项目内部文件结构:

tree ch06-cookies

ch06-cookies
├── WEB-INF
│   ├── classes
│   │   └── com
│   │       └── example
│   │           ├── CheckCookie.class
│   │           └── CookieTest.class
│   └── web.xml
├── cookieresult.jsp
└── form.html

每个项目下都必须有有个 web.xml 文件,它被叫做(Deployment Descriptor,DD),里面定义了路径和 servlet 的对应关系。
web.xml:


<web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
    <servlet>
        <servlet-name>Ch6_Cookie_Testservlet-name>
        <servlet-class>com.example.CookieTestservlet-class>
    servlet>

    <servlet-mapping>
        <servlet-name>Ch6_Cookie_Testservlet-name>
        <url-pattern>/cookietest.dourl-pattern>
    servlet-mapping>

    <servlet>
        <servlet-name>Ch6_Check_Cookieservlet-name>
        <servlet-class>com.example.CheckCookieservlet-class>
    servlet>

    <servlet-mapping>
        <servlet-name>Ch6_Check_Cookieservlet-name>
        <url-pattern>/checkcookie.dourl-pattern>
    servlet-mapping>

web-app>

这样的一对元素定义一个对应关系,这里定义了两个对应关系:

/cookietest.do=> com.example.CookieTest
”/checkcookie.do=> com.example.CheckCookie

所以:
http://localhost:8080/ch06-cookies/checkcookie.do 请求会被转发给 CheckCookie servlet 来处理。(在实际使用的时候还要确定是 GET 还是 POST,这里就先忽略了)。

框架做了太多的事情,降低了上手门槛,提高了开发效率,但也少了份明白。

练手的工程在这里,可以跑一跑。

你可能感兴趣的:(Spring,Boot学习笔记,servlet,tomcat,容器,关系,为什么)