深入了解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是开源的

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);
	}
}

分析:

第一步分析

可知这个抽象类继承了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中servlet的创建方式实现的文章就介绍到这了,更多相关tomcat servlet创建方式内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解Tomcat是如何实现异步Servlet的

    前言 通过我之前的Tomcat系列文章,相信看我博客的同学对Tomcat应该有一个比较清晰的了解了,在前几篇博客我们讨论了Tomcat在SpringBoot框架中是如何启动的,讨论了Tomcat的内部组件是如何设计以及请求是如何流转的,那么我们这边博客聊聊Tomcat的异步Servlet,Tomcat是如何实现异步Servlet的以及异步Servlet的使用场景. 手撸一个异步的Servlet 我们直接借助SpringBoot框架来实现一个Servlet,这里只展示Servlet代码: @Web

  • tomcat关于配置servlet的url-pattern的问题思路详解

    tomcat在配置web.xml的时候,servlet是一个比较重要的问题,在这里讨论一下servlet中的几个痛点 servlet url-pattern的匹配问题 url-pattern中 / 和 /* 的区别 url-pattern的优先级问题 根路径 / 的匹配问题 1 servlet url-pattern 的匹配问题 url-pattern 有三种匹配模式,分别是路径匹配.精确匹配.后缀匹配 1.1 精确匹配 <url-pattern> 中配置的项必须与url完全精确匹配. 代码举

  • tomcat中Servlet的工作机制详细介绍

    tomcat中Servlet的工作机制 在研究Servlet在tomcat中的工作机制前必须先看看Servlet规范的一些重要的相关规定,规范提供了一个Servlet接口,接口中包含的重要方法是init.service.destroy等方法,Servlet在初始化时要调用init方法,在销毁时要调用destroy方法,而对客户端请求处理时则调用service方法.对于这些机制的支持都必须由Tomcat内部去支持,具体则是由Wrapper容器提供支持. 在tomcat中消息流的流转机制是通过四个不

  • Tomcat怎么实现异步Servlet

    有时Servlet在生成响应报文前必须等待某些耗时的操作,比如在等待一个可用的JDBC连接或等待一个远程Web服务的响应.对于这种情况servlet规范中定义了异步处理方式,由于Servlet中等待阻塞会导致Web容器整体的处理能力低下,所以对于比较耗时的操作可以放置到另外一个线程中进行处理,此过程保留连接的请求和响应对象,在处理完成之后可以把处理的结果通知到客户端. 下面先看Servlet在同步情况下的处理过程,如图所示,Tomcat的客户端请求由管道处理最后会通过Wrapper容器的管道,这

  • tomcat中Servlet对象池介绍及如何使用

    tomcat中Servlet对象池 Servlet在不实现SingleThreadModel的情况下运行时是以单个实例模式,如下图,这种情况下,Wrapper容器只会通过反射实例化一个Servlet对象,对应此Servlet的所有客户端请求都会共用此Servlet对象,而对于多个客户端请求tomcat会使用多线程处理,所以应该保证此Servlet对象的线程安全,多个线程不管执行顺序如何都能保证执行结果的正确性.例如刚做web应用开发时可能会犯的一个错误:在某个Servlet中使用成员变量累加去统

  • servlet和tomcat_动力节点Java学院整理

    Servlet是什么 为了能让Web服务器与Web应用这两个不同的软件系统协作,需要一套标准接口,Servlet就是其中最主要的一个接口. 规定: Web服务器可以访问任意一个Web应用中实现Servlet接口的类. Web应用中用于被Web服务器动态调用的程序代码位于Servlet接口的实现类中. SUN公司(现在被Oracle收购了--)制定了Web应用于Web服务器进行协作的一系列标准Java接口(统称为Java Servlet API). SUN公司还对Web服务器发布及运行Web应用的

  • 详解如何通过tomcat的ManagerServlet远程部署项目

    介绍 之前在邮政实习时,leader让我阅读tomcat的源代码,尝试自己实现远程部署项目的功能,于是便有了这此实践. 在Tomact中有一个Manager应用程序,它是用来管理已经部署的web应用程序,在这个应用程序中,ManagerServlet是他的主servlet,通过它我们可以获取tomcat的部分指标,远程管理web应用程序,不过这个功能会受到web应用程序部署中安全约束的保护. 当你请求ManagerServlet时,它会检查getPathInfo()返回的值以及相关的查询参数,以

  • Spring关闭Tomcat Servlet容器时内存泄漏问题解决方案

    这篇文章主要介绍了Spring关闭Tomcat Servlet容器时内存泄漏问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 出错信息 22-Sep-2017 06:19:51.064 WARNING [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [license] appears t

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

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

  • Eclipse中使用Maven创建Java Web工程的实现方式

    Eclipse中使用Maven创建Java Web工程的实现方式 1)在Eclipse项目栏中右键单击空白,New(或直接使用Ctrl+N快捷键) -- Other --Maven Project. 2)选择以webapp模板创建工程 3)填写Group Id . Artifact Id 等信息. groupId 定义了项目属于哪个组,举个例子,如果你的公司是mycom,有一个项目为myapp,那么groupId就应该是com.mycom.myapp. artifacted 定义了当前maven

  • javascript中createElement的两种创建方式

    本文实例讲述了javascript中createElement的两种创建方式.分享给大家供大家参考.具体实现方法如下: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>CreateElement

  • Android中AlertDialog的六种创建方式

     创建AlertDialog的步骤: 1.创建AlertDialog.Builder对象 2.调用Builder对象的setTitle方法设置标题,setIcon方法设置图标 3.调用Builder相关方法如setMessage方法.setItems方法.setSingleChoiceItems方法.setMultiChoiceItems方法.setAdapter方法.setView方法设置不同类型的对话框内容. 4.调用setPositiveButton.setNegativeButton.s

  • Java多线程中线程的两种创建方式及比较代码示例

    1.线程的概念:线程(thread)是指一个任务从头至尾的执行流,线程提供一个运行任务的机制,对于java而言,一个程序中可以并发的执行多个线程,这些线程可以在多处理器系统上同时运行.当程序作为一个应用程序运行时,java解释器为main()方法启动一个线程. 2.并行与并发: (1)并发:在单处理器系统中,多个线程共享CPU时间,而操作系统负责调度及分配资源给它们. (2)并行:在多处理器系统中,多个处理器可以同时运行多个线程,这些线程在同一时间可以同时运行,而不同于并发,只能多个线程共享CP

  • JS中的函数与对象的创建方式

    创建函数的三种方式 1.函数声明 function calSum1(num1, num2) { return num1 + num2; } console.log(calSum1(10, 10)); 2.函数表达式 var calSum2 = function (num1, num2) { return num1 + num2; } console.log(calSum2(10, 20)); 3.函数对象方式 var calSum3 = new Function('num1', 'num2',

  • 在Python中通过threshold创建mask方式

    我就废话不多说了,直接上代码吧! [code] import numpy as np threshold=2 a=np.array([[1,2,3],[3,4,5]]) b=a>threshold print("a="+str(a)) print("b="+str(b)) [result] a=[[1 2 3] [3 4 5]] b=[[False False True] [ True True True]] 以上这篇在Python中通过threshold创建

  • Kotlin中实体类的创建方式

    类的基本格式 class 类名{ } 属性的基本格式 var 属性名字 : 类型 下面是实体类代码 package com.dldw.entity import java.util.* class Demo { //var 声明的属性可以被二次赋值 val声明的是不可变属性,赋值以后不能在赋值,否则编译报错 //长整型 64位 注意后面加大写L var height: Long? = 0L //整型 32 位 var id : Int?= 0 //短整型 16位 var short :Short

随机推荐