精华内容
下载资源
问答
  • 使用tomcat服务器创建Servlet应用程序的步骤 (Steps to Create Servlet Application using tomcat server) To create a Servlet application you need to follow the below mentioned steps. These steps are ...

    To create a Servlet application you need to follow the below mentioned steps. These steps are common for all the Web server. In our example we are using Apache Tomcat server. Apache Tomcat is an open source web server for testing servlets and JSP technology. Download latest version of Tomcat Server and install it on your machine.

    要创建Servlet应用程序,您需要执行以下提到的步骤。 这些步骤对于所有Web服务器都是通用的。 在我们的示例中,我们使用的是Apache Tomcat服务器。 Apache Tomcat是用于测试servlet和JSP技术的开源Web服务器。 下载最新版本的Tomcat服务器并将其安装在您的计算机上。

    After installing Tomcat Server on your machine follow the below mentioned steps :

    在您的机器上安装Tomcat Server之后,请执行以下提到的步骤:

    1. Create directory structure for your application.

      为您的应用程序创建目录结构。

    2. Create a Servlet

      创建一个Servlet

    3. Compile the Servlet

      编译Servlet

    4. Create Deployement Descriptor for your application

      为您的应用程序创建部署描述符

    5. Start the server and deploy the application

      启动服务器并部署应用程序

    All these 5 steps are explained in details below, lets create our first Servlet Application.

    下面将详细解释所有这5个步骤,让我们创建第一个Servlet应用程序。

    1.创建目录结构 (1. Creating the Directory Structure)

    Sun Microsystem defines a unique directory structure that must be followed to create a servlet application.

    Sun Microsystem定义了创建servlet应用程序必须遵循的唯一目录结构。

    servlet directory strucutre

    Create the above directory structure inside Apache-Tomcat\webapps directory. All HTML, static files(images, css etc) are kept directly under Web application folder. While all the Servlet classes are kept inside classes folder.

    Apache-Tomcat \ webapps目录中创建以上目录结构。 所有HTML,静态文件(图像,css等)都直接保存在Web应用程序文件夹下。 而所有的Servlet类都保存在classes文件夹中。

    The web.xml (deployement descriptor) file is kept under WEB-INF folder.

    web.xml (部署描述符)文件保存在WEB-INF文件夹下。

    2.创建一个Servlet (2. Creating a Servlet)

    There are three different ways to create a servlet.

    有三种创建servlet的方法。

    • By implementing Servlet interface

      通过实现Servlet接口

    • By extending GenericServlet class

      通过扩展GenericServlet

    • By extending HttpServlet class

      通过扩展HttpServlet

    But mostly a servlet is created by extending HttpServlet abstract class. As discussed earlier HttpServlet gives the definition of service() method of the Servlet interface. The servlet class that we will create should not override service() method. Our servlet class will override only doGet() or doPost() method.

    但是大多数情况下,通过扩展HttpServlet抽象类来创建servlet。 如前所述, HttpServlet给出了Servlet接口的service()方法的定义。 我们将创建的servlet类不应覆盖service()方法。 我们的Servlet类将仅覆盖doGet()doPost()方法。

    When a request comes in for the servlet, the Web Container calls the servlet's service() method and depending on the type of request the service() method calls either the doGet() or doPost() method.

    当收到对Servlet的请求时,Web容器将调用Servlet的service()方法,并且根据请求的类型, service()方法将调用doGet()doPost()方法。

    NOTE: By default a request is Get request.

    注意:默认情况下,请求是“ 获取请求”。

    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.io.*;
    
    public MyServlet extends HttpServlet
    {
    	public void doGet(HttpServletRequest request,HttpServletResposne response) 
    	                     throws ServletException {
    		response.setContentType("text/html");
    		PrintWriter out = response.getWriter();
    		out.println("<html><body>");
    		out.println("<h1>Hello Readers</h1>");
    		out.println("</body></html>");
    	}
    }

    Write above code in a notepad file and save it as MyServlet.java anywhere on your PC. Compile it(explained in next step) from there and paste the class file into WEB-INF/classes/ directory that you have to create inside Tomcat/webapps directory.

    将上述代码写在记事本文件中,并将其另存为PC上任何位置的MyServlet.java 。 从那里编译它(在下一步中解释),然后将类文件粘贴到必须在Tomcat / webapps目录中创建的WEB-INF/classes/目录中。

    3.编译Servlet (3. Compiling a Servlet)

    To compile a Servlet a JAR file is required. Different servers require different JAR files. In Apache Tomcat server servlet-api.jar file is required to compile a servlet class.

    要编译Servlet,需要JAR文件。 不同的服务器需要不同的JAR文件。 在Apache Tomcat服务器中,编译Servlet类需要servlet-api.jar文件。

    Steps to compile a Servlet:

    编译Servlet的步骤:

    • Set the Class Path.

      设置类路径。

    • compiling a Servlet
    • Download servlet-api.jar file.

      下载servlet-api.jar文件。

    • Paste the servlet-api.jar file inside Java\jdk\jre\lib\ext directory.

      将servlet-api.jar文件粘贴到Java\jdk\jre\lib\ext目录中。

    • compiling a Servlet
    • Compile the Servlet class.

      编译Servlet类。

    • compiling a Servlet

    NOTE: After compiling your Servlet class you will have to paste the class file into WEB-INF/classes/ directory.

    注意:编译Servlet类后,必须将类文件粘贴到WEB-INF/classes/目录中。

    4.创建部署描述符 (4. Create Deployment Descriptor)

    Deployment Descriptor(DD) is an XML document that is used by Web Container to run Servlets and JSP pages. DD is used for several important purposes such as:

    部署描述符(DD)是一个XML文档,Web容器使用它来运行Servlet和JSP页面。 DD用于几个重要目的,例如:

    • Mapping URL to Servlet class.

      将URL映射到Servlet类。

    • Initializing parameters.

      初始化参数。

    • Defining Error page.

      定义错误页面。

    • Security roles.

      安全角色。

    • Declaring tag libraries.

      声明标签库。

    We will discuss about all these in details later. Now we will see how to create a simple web.xml file for our web application.

    稍后我们将详细讨论所有这些内容。 现在,我们将看到如何为我们的Web应用程序创建一个简单的web.xml文件。

    web.xml file

    5.启动服务器 (5. Start the Server)

    Double click on the startup.bat file to start your Apache Tomcat Server.

    双击startup.bat文件以启动您的Apache Tomcat服务器。

    Or, execute the following command on your windows machine using RUN prompt.

    或者,在Windows机器上使用RUN提示符执行以下命令。

    C:\apache-tomcat-7.0.14\bin\startup.bat
    
    

    6.首次启动Tomcat服务器 (6. Starting Tomcat Server for the first time)

    If you are starting Tomcat Server for the first time you need to set JAVA_HOME in the Enviroment variable. The following steps will show you how to set it.

    如果是第一次启动Tomcat Server,则需要在Enviroment变量中设置JAVA_HOME。 以下步骤将向您展示如何进行设置。

    • Right Click on My Computer, go to Properites.

      右键单击“ 我的电脑” ,转到“ 属性”

    • setting JAVA_HOME for Tomcat
    • Go to Advanced Tab and Click on Enviroment Variables... button.

      转到高级选项卡,然后单击环境变量...按钮。

    • setting JAVA_HOME for Tomcat
    • Click on New button, and enter JAVA_HOME inside Variable name text field and path of JDK inside Variable value text field. Click OK to save.

      单击“ 新建”按钮,然后在“变量名”文本字段内输入JAVA_HOME ,在“变量值”文本字段内输入JDK的路径。 单击确定保存。

    • setting JAVA_HOME for Tomcat

    7.运行Servlet应用程序 (7. Run Servlet Application)

    Open Browser and type http:localhost:8080/First/hello

    打开浏览器,然后输入http:localhost:8080 / First / hello

    Running first servlet application

    Hurray! Our first Servlet Application ran successfully.

    欢呼! 我们的第一个Servlet应用程序成功运行。

    翻译自: https://www.studytonight.com/servlet/steps-to-create-servlet-using-tomcat-server.php

    展开全文
  • Tomcat如何创建Servlet? A.先到缓存中寻找有没有这个对象 如果没有: 1、通过反射去创建相应的对象(执行构造方法)  2、tomcat会把对象存放到缓存中  3、执行初始化方法init 如果有该对象,直接获取到这个...

    Tomcat如何创建Servlet?

    A.先到缓存中寻找有没有这个对象
    如果没有: 1、通过反射去创建相应的对象(执行构造方法)
       2、tomcat会把对象存放到缓存中
       3、执行初始化方法init
    如果有该对象,直接获取到这个对象
    B. 执行服务方法
    C.返回响应的数据到客户端(浏览器)


    Servlet的执行流程

    一:从浏览器地址(请求)开始分析
    1.http://localhost:80/servlet/hello

    2.  Localhost:80 -> 找到我们的服务器
      3.  到tomcat的server.xml中找到 Context 这个配置
    <Context docBase="E:\java\javaee\day13-servlet\webapps" path="servlet" />
    4.  servlet: 这个Servlet找到Context中的path
      5.  通过path找到它对应的docBase,也就是找到我们工程实际地址
    6.  Hello 就到我们实现的项目中找到相应的
                    web.xml文件中的servlet-mapping中的url-pattern
     

    二、分析web.xml中的内容

    1 先找到url-pattern  -》 <url-pattern>/hello</url-pattern>
    2. 找到它对应的servlet-name
    3 .通过mapping中servlet-name找到相应的servlet(它们的servet-name是一样的)
    在servlet标签中找到它的servlet-class,它里面是全限定名称












    展开全文
  • 深入了解tomcatservlet创建方式

    千次阅读 多人点赞 2020-10-11 12:00:17
    深入了解tomcatservlet创建方式 1什么是servlet 1.1、用官方的话解释: Servlet是oracle公司提供的一门用于开发动态web资源的技术,属于javaEE体系中的一种核心规范。 通俗解释一下:就是我们开发人员所编写的一...

    深入了解tomcat中servlet的创建方式

    一、 什么是servlet

    1.1、用官方的话解释:
    Servlet是oracle公司提供的一门用于开发动态web资源的技术,属于javaEE体系中的一种核心规范。
    通俗解释一下:就是我们开发人员所编写的一个类,必须直接或者间接实现这个javaEE的核心规范,也就是实现Servlet接口,因为这种类产生的对象可以被浏览器访问到,因此称之为Servlet,并且javaEE中规定了只有Servlet的实现类产生的对象才可以被浏览器访问,就是Servlet.(也就是说这个类要直接或者间接实现了Servlet接口)

    二、开始进入servlet的创建

    2.1、通过前面介绍,我们知道了一个什么样的类创建的对象可以被浏览器访问,首先我们直接上代码:

    package com.briup.web;
    import java.io.IOException;
    import javax.servlet.Servlet;
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    public class FirstWay implements Servlet {
    	public FirstWay() {
    		System.out.println("对象创建了");
    	}
    	@Override
    	public void init(ServletConfig config) throws ServletException {
    		// TODO Auto-generated method stub
    		System.out.println("我是init:我被调用了");
    	}
    	@Override
    	public ServletConfig getServletConfig() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    	@Override
    	public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		System.out.println("我是service,我被调用了");	
    	}
    	@Override
    	public String getServletInfo() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    	@Override
    	public void destroy() {
    		// TODO Auto-generated method stub
    		System.out.println("我是destory:我被调用了");
    	}
    
    }
    
    

    那么,一个满足servlet的类已经创建好了,接下来抛出疑问

    • servet对象由谁创建?
    • 里面实现的接口方法,哪些会调用,什么时候调用,调用几次?
      第一个疑问: 既然是servlet类,由我们开发人员自己手动创建对象,显然是不合理,所以这个对象的创建,是交给tomcat创建的,我们开发人员只需要告诉 tomcat,让他创建,让他什么时候创建就行了;
      如何告诉?

    1、方法一:通过配置webxml的方式。(极其不推荐使用

    对于整个动态web项目而言,web.xml是最先加载的配置文件,所以在web.xml的方式配置

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
      <display-name>firstWay</display-name>
      <servlet>
      		<servlet-name>FirstWay</servlet-name>
      		<servlet-class>com.briup.web.FirstWay</servlet-class>
      		<!-- <load-on-startup>1</load-on-startup> -->
      </servlet>
      <servlet-mapping>
      	<servlet-name>FirstWay</servlet-name>
      	<url-pattern>/FirstWay</url-pattern>
      </servlet-mapping>
    </web-app>
    

    解释:
    1、servlet-name:见名知意:servlet的名字,注意要与下面你设置映射的名字对应
    2、serlvet-class:serlvet的全限定名
    3、load-on-startup:是否在tomcat启动的时候就创建servlet对象,传入一个大于0的整数‘’(默认是浏览器第一次请求的时候创建servlet对象
    4、servlet-mapping:见名知意,设置浏览器的访问映射
    5、servlet-name:于上面的对应
    6、url-pattern:浏览器的访问映射(假设默认是本机的话,且tomcat的端口号为8080,那么浏览器访问这个servlet的路径为:localhost:8080/项目名/FirstWay
    有了这些基础,让我们访问看看;

    • 第一步:启动tomcat
      在这里插入图片描述
      tomcat正常启动
    • 第二步:通过浏览器访问(我们这里手动访问3次)
      在这里插入图片描述
      浏览器访问正常
    • 第三步:观察控制台
      在这里插入图片描述

    通过运行结果分析:

    • 第一次启动服务器,对象并没有被创建
    • 浏览器请求三遍,但是对象只创建一次,init()方法也只调用一次
    • 每访问一次,对象便会调用一次service()方法
    • 其他方法没被调用
      解释为嘛没被调用:getServletConfig():得到ServletConfig对象
      : getServletInfo():得到Servlet的信心,比如作者
      :destroy():servlet销毁的时候才会调用这个方法,(比如:tomcati正常关闭 这里我就不去测试,想测试的小伙伴,可以右键service,点击stop)然后再观察控制台便可知了。

    2、方法二:注解的方式告诉tomcat(与前者相比,推荐使用

    @WebServlet(value ="映射路径")
    public Fristservlet implement Servelt {
    }
    

    通过这个注解也可以设置,是否在启动服务器的时候就创建对象,这里就不演示了,
    注意:(一旦使用了注解的方式告诉tomcat如果创建某个对象,就不能在web.xml里面再对这个servlet进行访问设置了

    三、回归主题,servlet的第二种创建方式

    有了前面的解释,直接上代码然后再分析

    package com.briup.web;
    
    import java.io.IOException;
    
    import javax.servlet.GenericServlet;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.annotation.WebServlet;
    @WebServlet(value = "/secondWay")
    public class SecondWayCreate extends GenericServlet {
    
    	@Override
    	public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		System.out.println("调用了service方法");
    	}
    
    }
    
    
    • 1、比第一种方法简洁,实现的是GenericServlet这个类
    • 2、我们看一下GenericServlet源码,然后进行分析;
    public abstract class GenericServlet implements Servlet, ServletConfig,
    

    可知,这是个抽线类,是servlet接口的实现类,那么GenericServlet间接 实现了servlet接口,
    与第一种方式相比:开发者不是必须将一些接口中不必要的方法实现,可以具有选择性,减少了代码量。然而并没有上面ruan用,就是装b而已

    三、重点第三种方式(与前两者相比,我更推荐第三种方式)

    直接上代码

    package com.briup.web;
    
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    @WebServlet(value = "/ThreeWayCreate")
    public class ThreeWayCreate extends HttpServlet {
    	@Override
    	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		super.doGet(req, resp);
    	}
    	@Override
    	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		super.doPost(req, resp);
    	}
    }
    
    

    通过以上代码,可能就有小伙伴要问了
    不是说servlet要直接或者间接实现servlet接口吗,不是说浏览器每请求一次就要调用一次service方法吗?方法在哪呢?这不是与前面理论冲突了吗?
    我们继续看源码,源码才是道理
    我在下面值列举源码里面比较核心的部分,需要理解更加深入了解的小伙伴,直接去看源码,tomcat是开源的

    public abstract class HttpServlet extends GenericServlet {
    	 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
        {
            String protocol = req.getProtocol();
            String msg = lStrings.getString("http.method_get_not_supported");
            if (protocol.endsWith("1.1")) {
                resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
            } else {
                resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
            }
        }
         protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
    
            String protocol = req.getProtocol();
            String msg = lStrings.getString("http.method_post_not_supported");
            if (protocol.endsWith("1.1")) {
                resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
            } else {
                resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
            }
        }
    
    }
    
    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);
            }
        }
    
    
        /*
         * Sets the Last-Modified entity header field, if it has not
         * already been set and if the value is meaningful.  Called before
         * doGet, to ensure that headers are set before response data is
         * written.  A subclass might have set this header already, so we
         * check.
         */
          public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException {
    
            HttpServletRequest  request;
            HttpServletResponse response;
    
            try {
                request = (HttpServletRequest) req;
                response = (HttpServletResponse) res;
            } catch (ClassCastException e) {
                throw new ServletException("non-HTTP request or response");
            }
            service(request, response);
        }
    }
    }
    

    分析:

    • 第一步分析
      在这里插入图片描述
      可知这个抽象类继承了GennericeServlet这个抽象类 也就是逐层往下推,实现了Servle接口,那么这个抽线类必然也继承了serice方法。
    • 第二步分析
      在这里插入图片描述
      这个是继承servlet接口的service方法,当浏览器每请求一次时,都会调用这个方法,由图可知,这个方法已经被HttpServlet实现了,由实现类可以得出,请求对象req,和响应对象res,被强转成了HttpServletRequest,和HttpServletResponse(向下转型),然后将强转的对象,传入HttpServlet重载的Service方法中,调用,第三步,分析重载后的Service(HttpRequest req,HttpRespone res);
    • 第三步分析
      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);
            }
        }
    
    

    通过传过来的HttpRequest对象,判断请求方式,通过请求方式,决定调用哪个方法(如果请求方式是post方式,那么就会调用doPost(HttpRequest req,HttpRestpone Res)方法

    • 第四步分析
      综上分析,总结:tomcat创建对象,当浏览器请求的时候,调用Servlet的Service(ServeltRequest req,ServletRespone res )方法,然后这个方法再调用,HttpServlet里面重载的Servlet(HttpServletReqeust req ,HttpServletRespone res)方法,然后这个方法会通过请求方式是什么,选择性的调用doPost(),还是doGet()方法(当然还有很多其他的方式这里就不列举了),
    因此第三种方式,的本质还是当浏览器发起一次请求的时候调用了Servlet接口里面的Service(ServeltRequest req,ServletRespone res )方法,然后通过实现类的里面的逻辑,间接的调用了doPost()等方法。

    优点:

    • 1、通过请求方式可以处理相应的请求,使得逻辑更加清晰
    • 2,减少代码量,是程序更加简洁
    • 3,使得请求或者响应的操作性更加丰富
    • 4…

    四、 总结:

    注意点:浏览器发起请求调用的一定是servlet种的service方法;
    有任何错误或者见解希望各位读者指出互相进步,相互学习。

    展开全文
  • 上一篇博客我们将tomcat源码在本地成功运行了,所以在本篇博客中我们从源码层面分析,tomcat在启动的过程中,是如何初始化servlet容器的。我们平常都是将我们的服务部署到 tomcat中,然后修改一下配置文件,启动就...

    引言

    上一篇博客我们将tomcat源码在本地成功运行了,所以在本篇博客中我们从源码层面分析,tomcat在启动的过程中,是如何初始化servlet容器的。我们平常都是将我们的服务部署到 tomcat中,然后修改一下配置文件,启动就可以对外提供 服务了,但是我们对于其中的一些流程并不是非常的了解,例如如何加载的web.xml等。这是我们分析servlet 和 sringMVC必不可少的过程。

    注释源码地址:https://github.com/good-jack/tomcat_source/tree/master

    一、代码启动tomcat

    平常我们不论是Windows还是linux,我们都是通过脚本来启动tomcat,这对于我们分析源码不是很友好,所以我们 需要通过代码启动,启动代码如下:

    Tomcat tomcat = new Tomcat();
            tomcat.setPort(8080);
            //new 出各层容器,并且维护各层容器的关系
            tomcat.addWebapp("/","/");
            tomcat.start();
            //阻塞监听端口
            tomcat.getServer().await();

    启动代码还是非常非常简单,从代码中我们就可以看出,我们本篇博客主要分析的就是 addWebapp()方法和start()方法,通过这两个方法我们就可以找到servlet容器是在什么时候被初始化的。

    二、tomcat框架 

    在我们进行分析上面两个方法之前,我们先总结一下tomcat的基础框架,其实从我们非常熟悉的 server.xml配置文件中就可以知道,tomcat就是一系列父子容器组成:

    Server   --->  Service   -->   Connector   Engine addChild--->   context(servlet容器) ,这就是我们从配置文件中分析出来的几个容器,tomcat启动时候就是逐层启动容器。

    三、创建容器(addWebapp())

    3.1 方法 调用流程图

    上面的流程图就是,从源码中逐步分析出来的几个重要的方法,这对于我们分析源码非常有帮助。

    3.2 源码分析

    1)通过反射获得configContext监听器

    方法路径:package org.apache.catalina.startup.Tomcat.addWebapp(Host host, String contextPath, String docBase);

    
        public Context  addWebapp(Host host, String contextPath, String docBase) {
            //通过反射获得一个监听器  ContextConfig,
            //通过反射得到的一定是LifecycleListener的一个实现类,进入getConfigClass得到实现类(org.apache.catalina.startup.ContextConfig)
            LifecycleListener listener = null;
            try {
                Class<?> clazz = Class.forName(getHost().getConfigClass());
                listener = (LifecycleListener) clazz.getConstructor().newInstance();
            } catch (ReflectiveOperationException e) {
                // Wrap in IAE since we can't easily change the method signature to
                // to throw the specific checked exceptions
                throw new IllegalArgumentException(e);
            }
    
            return addWebapp(host, contextPath, docBase, listener);
        }

     2) 获得一个context容器(StandardContext)

    在下面代码中,createContext()方法通过反射加载StandardContext容器,并且将设置监听ContextConfig, ctx.addLifecycleListener(config);

    public Context addWebapp(Host host, String contextPath, String docBase,
                LifecycleListener config) {
    
            silence(host, contextPath);
    
            //获得一个context容器(StandardContext)
            Context ctx = createContext(host, contextPath);
            ctx.setPath(contextPath);
            ctx.setDocBase(docBase);
    
            if (addDefaultWebXmlToWebapp) {
                ctx.addLifecycleListener(getDefaultWebXmlListener());
            }
    
            ctx.setConfigFile(getWebappConfigFile(docBase, contextPath));
            //把监听器添加到context中去
            ctx.addLifecycleListener(config);
    
            if (addDefaultWebXmlToWebapp && (config instanceof ContextConfig)) {
                // prevent it from looking ( if it finds one - it'll have dup error )
                ((ContextConfig) config).setDefaultWebXml(noDefaultWebXmlPath());
            }
    
            if (host == null) {
                //getHost会逐层创建容器,并维护容器父子关系
                getHost().addChild(ctx);
            } else {
                host.addChild(ctx);
            }
    
            return ctx;
        }

    3)维护各层容器

    getHost()方法中得到各层容器,并且维护父亲容器关系,其中包括,server容器、Engine容器。并且将StandardContext容器通过getHost().addChild(ctx); 调用containerBase中的addChild()方法维护在 children 这个map中。

      public Host getHost() {
            //将每一层的容器都new 出来
            Engine engine = getEngine();
            if (engine.findChildren().length > 0) {
                return (Host) engine.findChildren()[0];
            }
    
            Host host = new StandardHost();
            host.setName(hostname);
            //维护tomcat中的父子容器
            getEngine().addChild(host);
            return host;
        }

    getEngine().addChild(host); 方法选择调用父类containerBase中的addChild方法

      @Override
        public void addChild(Container child) {
            if (Globals.IS_SECURITY_ENABLED) {
                PrivilegedAction<Void> dp =
                    new PrivilegedAddChild(child);
                AccessController.doPrivileged(dp);
            } else {
                //这里的child 参数是 context 容器
                addChildInternal(child);
            }
        }

     addChildInternal()方法的 核心代码

     private void addChildInternal(Container child) {
    
            if( log.isDebugEnabled() )
                log.debug("Add child " + child + " " + this);
            synchronized(children) {
                if (children.get(child.getName()) != null)
                    throw new IllegalArgumentException("addChild:  Child name '" +
                                                       child.getName() +
                                                       "' is not unique");
                child.setParent(this);  // May throw IAE
                children.put(child.getName(), child);
        }

    四、启动容器(tomcat.start())

    4.1、方法调用流程图

    4.2、源码分析

    说明:StandardServer 、StandardService、StandardEngine等容器都是继承LifecycleBase

    所以这里是模板模式的经典应用

    1)逐层启动容器

    此时的server对应的是我们前面创建的StandardServer

      public void start() throws LifecycleException {
            //防止server容器没有创建
            getServer();
            //获得connector容器,并且将得到的connector容器设置到service容器中
            getConnector();
            //这里的start的实现是在 LifecycleBase类中实现
            //LifecycleBase方法是一个模板方法,在tomcat启动流程中非常关键
            server.start();
        }

    2) 进入start方法

    进入LifecycelBase中的start方法,其中核心方法是startInternal。

     

     从上面我们知道现在我们调用的是StandardServer容器的startInternal()方法,所以我们这里选择的是StandardServer

    方法路径:org.apache.catalina.core.StandardServer.startInternal()

    protected void startInternal() throws LifecycleException {
    
            fireLifecycleEvent(CONFIGURE_START_EVENT, null);
            setState(LifecycleState.STARTING);
    
            globalNamingResources.start();
    
            // Start our defined Services
            synchronized (servicesLock) {
                //启动 service容器,一个tomcat中可以配置多个service容器,每个service容器都对应这我们的一个服务应用
                for (Service service : services) {
                    //对应 StandardService.startInternal()
                    service.start();
                }
            }
        }

    从上面代码中我们可以看出,启动server容器的时候需要启动子容器 service容器,从这里开始就是容器 逐层向向内引爆,所以接下来就是开始依次调用各层容器的star方法。在这里就不在赘述。

    2)ContainerBase中的startInternal()方法 核心代码,从这开始启动StandardContext容器

     // Start our child containers, if any
            //在addWwbapp的流程中 addChild方法中加入的,所以这里需要找出来
            //这里找出来的就是 context 容器
            Container children[] = findChildren();
            List<Future<Void>> results = new ArrayList<>();
            for (Container child : children) {
                //通过线程池 异步的方式启动线程池 开始启动 context容器,进入new StartChild
                results.add(startStopExecutor.submit(new StartChild(child)));
            }
    

    new StartChild(child)) 方法开始启动StandardContext容器

        private static class StartChild implements Callable<Void> {
    
            private Container child;
    
            public StartChild(Container child) {
                this.child = child;
            }
    
            @Override
            public Void call() throws LifecycleException {
                //开始启动context,实际调用 StandardContext.startInternal()
                child.start();
                return null;
            }
        }

    StandardContext.startInternal() 方法中的核心代码:

       protected void fireLifecycleEvent(String type, Object data) {
            LifecycleEvent event = new LifecycleEvent(this, type, data);
            //lifecycleListeners 在addwebapp方法的第一步中,设置的监听的 contextConfig对象
            for (LifecycleListener listener : lifecycleListeners) {
                //这里调用的是 contextConfig的lifecycleEvent()方法
                listener.lifecycleEvent(event);
            }
        }

     进入到 contextConfig中的lifecycleEvent()方法

    public void lifecycleEvent(LifecycleEvent event) {
    
            // Identify the context we are associated with
            try {
                context = (Context) event.getLifecycle();
            } catch (ClassCastException e) {
                log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e);
                return;
            }
    
            // Process the event that has occurred
            if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
                //完成web.xml的内容解析
                configureStart();
            } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
                beforeStart();
            } else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {
                // Restore docBase for management tools
                if (originalDocBase != null) {
                    context.setDocBase(originalDocBase);
                }
            } else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) {
                configureStop();
            } else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) {
                init();
            } else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) {
                destroy();
            }
    
        }

     在上面方法中,完成对web.xml的加载和解析,同时加载xml中配置的servlet并且封装成wrapper对象。

    3)、启动servlet容器,StandardContext.startInternal()  中的 loadOnStartup(findChildren())方法

    public boolean loadOnStartup(Container children[]) {
    
            // Collect "load on startup" servlets that need to be initialized
            TreeMap<Integer, ArrayList<Wrapper>> map = new TreeMap<>();
            for (Container child : children) {
                //这里的 Wrapper就是 我们前面封装的 servlet
                Wrapper wrapper = (Wrapper) child;
                int loadOnStartup = wrapper.getLoadOnStartup();
                if (loadOnStartup < 0) {
                    continue;
                }
                Integer key = Integer.valueOf(loadOnStartup);
                ArrayList<Wrapper> list = map.get(key);
                if (list == null) {
                    list = new ArrayList<>();
                    map.put(key, list);
                }
                list.add(wrapper);
            }
    
            // Load the collected "load on startup" servlets
            for (ArrayList<Wrapper> list : map.values()) {
                for (Wrapper wrapper : list) {
                    try {
                        //通过 load 方法  最终会调用 servlet的init方法
                        wrapper.load();
                    } catch (ServletException e) {
                        getLogger().error(sm.getString("standardContext.loadOnStartup.loadException",
                              getName(), wrapper.getName()), StandardWrapper.getRootCause(e));
                        // NOTE: load errors (including a servlet that throws
                        // UnavailableException from the init() method) are NOT
                        // fatal to application startup
                        // unless failCtxIfServletStartFails="true" is specified
                        if(getComputedFailCtxIfServletStartFails()) {
                            return false;
                        }
                    }
                }
            }
            return true;
    
        }

    通过 load 方法  最终会调用 servlet的init方法。

    五、总结

    上面内容就是整个tomcat是如何调用servlet初始化方法的流程,整个流程小编的理解,如果有错误,欢迎指正,小编已经在源码中重要部分进行了注释,所以如果有需要的各位读者,可以下载我的注释 源码,注释源码地址:

    https://github.com/good-jack/tomcat_source/tree/master

    展开全文
  • 2.在web/WEB-INF目录下新建两个文件夹,classes用于存放servlet的字节码文件(.class),lib用于存放项目引用的包。 3.按f4进入Project Structure,进入Modules(IDEA的工程)选项卡,将Paths的两个输出路径均...
  • 查了资料才知道原来在Tomcat 10中把包名从以往版本的javax改成了jakarta,而maven导包的时候依旧使用原来的javax,导致Tomcat 10服务器的Servlet接口和我写的servlet文件不匹配,从而无法正常运行。
  • servlet初识之创建servlettomcat配置

    千次阅读 2018-03-26 22:57:33
    Servlet初识 简介 Servlet 小服务程序 是个java类 是个接口 注意:在浏览器上访问的每一个网页都是一个servlet 每个servlet都需要配置一个网址 在web.xml中配置 apache-tomcat-9.0.0.M26 需要先下载...
  • Tomcat启动时创建Servlet

    2019-11-06 12:33:56
    有些servlet需要tomcat启动时被创建初始化,而不是serelvet第一次访问时开始创建 需要在web.xml中添加<load-on-startup>元素 元素值必须是一个大于零的整数 所有添加了<load-on-startup>元素的...
  • Tomcat创建网站和Servlet

    2020-03-27 16:58:27
    动态网站结构】 src:存放Java文件 web:静态资源文件和配置文件(WEB-INF/web.xml) 【指定Tomacat管理的网站】 【Run】---【Edit Configuration】---自己的tomcat管理---【Deployment】---添加需要被...
  • Tomcat反射加载servlet

    2019-04-07 10:26:48
    2.创建servlet(即可以在网页上运行的java程序代码) 必须实现Servlet接口才行 package com.it666.servlet; public class FirstSevlet implements Servlet{ //还有其他方法要覆盖,这里主要选取一个方法来讲解...
  • Tomcat servlet 配置

    2017-10-14 16:59:07
    Tomcatservlet的配置 和 简单入门案列
  • tomcat启动加载Servlet源码浅析

    千次阅读 2019-06-22 14:16:00
    我们知道tomcat不只是web服务器,它还提供动态地内容是一个Servlet容器。tomcat的总体架构如图所示: Server表示一个服务器实例,由Connector和Container组成Service服务。Connector用于接收请求,Container表示一...
  • Java WEB 篇八 tomcat 容器是如何创建 servlet 类实例?用到了什么原 理?
  • Servlet是oracle公司提供的一门用于开发动态web资源的技术,属于javaEE体系中的一种核心规范。 通俗解释一下:就是我们开发人员所编写的一个类,必须直接或者间接实现这个javaEE的核心规范,也就是实现Servlet接口,...
  • Tomcat-Servlet3.0

    2020-04-06 11:16:13
    web 软件架构 C/S:客户端/服务器端 B/S:浏览器/服务器端 ...静态资源:所有用户访问后,得到的结果都是一样的,称为静态资源....动态资源:每个用户访问相同资源后,得到的结果可能不一样。...如:servlet/jsp,php...
  • 使用IntelliJ IDEA配置Tomcat创建Servlet的步骤 1.新建WEB工程 2.在web/WEB-INF目录下新建两个文件夹,classes用于存放servlet的字节码文件(.class),lib用于存放项目引用的包。 3.按f4进入Project ...
  • Tomcat服务器启动时创建Servlet

    千次阅读 2018-07-21 23:57:45
    ------------------------Tomcat服务器启动时创建Servlet----------------------- Tomcat启动时创建Servlet 有些Servlet需要在Tomcat启动时就被创建,而不是第一次访问时被创建,那么可以在web.xml文件中配置&...
  • 求解:Tomcat实例化Servlet类异常?

    千次阅读 2021-01-03 01:12:32
    求解:运行web项目时报错实例化...环境变量已经配置完成,tomcat使用的是9.0.37 包也已经创建好 javabean包 WEB-INF>classes>mybean>data> javaservlet包 WEB-INF>classes>muservlet>control&
  • 当容器启动时,会读取在webapps目录下所有的web应用中的web.xml文件,然后对xml文件进行解析,并读取servlet注册信息。然后,将每个应用中注册的servlet类都进行加载,并通过反射的方式实例化。(有时候也是在第一次...
  • javaWeb的项目的创建。 avaee的项目需要存放到相关的容器中进行应用,application Server服务器的配置信息。 SDK:系统依赖开发的组件的形成,也急速hi...servlet 的容器存放在tomcat中进行执行环境的依赖结果。 ...
  • IDEA2020 tomcat10 servlet 较新版本 踩坑记录

    千次阅读 多人点赞 2021-04-14 23:21:41
    点击下面的+号,选择jars or dirxxxxxxxx,选择刚创建的lib目录,让选择目录用处的话,选择jar direxxxxxxx,打上勾,点击apply,OK 5: 将tomcat/lib目录下的servlet-api.jar复制到我们创建的lib目录里。...
  • TomcatServlet的笔记

    千次阅读 2017-10-26 21:08:44
    突然想研究一下,Tomcat服务器和Servlet的关系。一.Tomcat的模块结构和简单流程看了很多关于介绍Tomcat服务器的资料,这里写一个总结。Tomcat服务器主要有几个模块构成 ,Server,Service,Connector,Container...
  • TomcatServlet

    2018-03-07 22:32:28
    这同样是个老生常谈的话题,但是看再多也没有自己梳理一遍清楚,而且每过一遍,对于容器的认知就更加清晰,要知道...Tomcat在开发之中主要作为web容器,其本身完全由Java代码编写,可以用来作为servlet的容器,并且...
  • servlet工作原理之tomcat

    千次阅读 2019-06-10 10:34:13
    本文要点: 1、servlet容器即包含wrapper的context容器 2、servelt的config、request、response、session、context等均使用了门面模式 3、listener,事件监听器在tomcat启动,容器以及servlet生命周期中的应用。
  • 使用eclipse配置tomcat及新建servlet项目

    千次阅读 2019-06-24 11:07:29
    打开刚刚创建的文件,已经写好了很多东西。  下面我们把他部署到tomcat上 ,右键,然后一直next就可以 最后我们打开网址,看一下  说明部署成功,为什么会有上面的显示呢? 好了,这就是...
  • Servlet项目创建TomCat 8.5.59 + Windows 10 + IDEA2020.2.3) 安装TomCat 1. 下载 前往tomcat官网找到适合本机的版本: 点击后开始下载,大概10+MB的压缩包。下载后随便找一个地方解压就行,TomCat自己会自动...
  • Tomcat如何与Servlet对象进行交互Tomcat 是Web应用服务器,是一个Servlet/JSP容器. Tomcat 作为Servlet容器,负责处理客户请求,把请求传送给Servlet,并将Servlet的响应传送回给客户.而Servlet是一种运行在支持Java语言...
  • Tomcat在$ CATALINA_BASE/conf/web.xml中默认定义了两个Servlet:DefaultServlet和JspServlet,而且由于$ CATALINA_BASE/conf/web.xml为Web应用的默认部署描述文件,因此这两个Servlet会默认存在所有Web应用容器中。...
  • Tomcat中手动部署servlet

    千次阅读 2017-01-22 18:48:39
    1、按照《在Tomcat中手动部署...2、创建一个servlet源代码文件,如:HelloServlet.java import java.io.*; import javax.servlet.*; public class HelloServlet extends GenericServlet { public void servic
  • TomcatServlet之间的关系

    万次阅读 多人点赞 2018-01-17 14:22:28
    Servlet(小服务程序)是一个与协议无关的、跨平台的Web组件,它基于Java技术开  发,由Servlet容器所管理。和运行在客户端浏览器中的... Servlet的主要功能是交互式地浏览和修改数据,生成动态Web内容。  S

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 187,481
精华内容 74,992
关键字:

tomcat动态生成servlet