深入了解tomcat中servlet的创建方式实现
Tomcat如何创建Servlet?
A.先到缓存中寻找有没有这个对象(Servlet是单实例的,只会创建一次)
如果没有:
1、通过反射去创建相应的对象(执行构造方法)
2、tomcat会把对象存放到缓存中
3、执行初始化方法init
B.执行服务方法(Service方法)
C.返回响应的数据到客户端(浏览器
一、 什么是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用,就是装13而已
三、重点第三种方式(与前两者相比,我更推荐第三种方式)
直接上代码
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方法
转载地址:https://www.jb51.net/article/197292.htm
深入了解tomcat中servlet的创建方式实现的更多相关文章
- tomcat中Servlet的工作机制
在研究Servlet在tomcat中的工作机制前必须先看看Servlet规范的一些重要的相关规定,规范提供了一个Servlet接口,接口中包含的重要方法是init.service.destroy等方法 ...
- 关于tomcat中Servlet对象池
Servlet在不实现SingleThreadModel的情况下运行时是以单个实例模式,如下图,这种情况下,Wrapper容器只会通过反射实例化一个Servlet对象,对应此Servlet的所有客户端 ...
- tomcat中servlet冲突问题
在启动tomcat以后,控制台发现“Offending class: javax/servlet/Servlet.class”信息: 信息: validateJarFile(E:\code\MyApp ...
- 在Tomcat中采用基于表单的安全验证
.概述 (1)基于表单的验证 基于From的安全认证可以通过TomcatServer对Form表单中所提供的数据进行验证,基于表单的验证使系统开发者可以自定义用户的登陆页面和报错页面.这种验证方法 ...
- 在tomcat中加入SSL腾讯云证书的步骤
在tomcat中加入SSL证书,可以用https方式访问域名,增加域名的安全性.当然也有很多应用要求https访问,也是安全性的考虑.阿里云和腾讯云都提供SSL证书,还有一些其他的大公司也提供,我这里 ...
- Servlet 三种创建方式
servlet 是运行在 Web 服务器(tomcat)中的小型 Java 程序(即:服务器端的小应用程序) (其实就是一个java类,只不过不用再new了).servlet 通常通过 HTTP(超文 ...
- JavaWeb中servlet读取配置文件的方式
我们在JavaWeb中常常要涉及到一些文件的操作,比如读取配置文件,下载图片等等操作.那我们能不能采用我们以前在Java工程中读取文件的方式呢?废话不多说我们来看看下我们以前在Java工程中读取文件是 ...
- Tomcat中的Host和Engine级别的servlet容器
这边文章主要介绍的是Host容器 和 Engine容器.如果你想在同一个Tomcat上部署运行多个Context容器的话,你就需要使用Host容器,从理论上来讲,如果你的Tomcat只想要部署一个Co ...
- Servlet三种创建方式
直接实现 Servlet 接口不太方便,所以 Servlet 又内置了两个 Servlet 接口的实现类(抽象类),分别为 GenericServlet 和 HttpServlet,因此,创建 Ser ...
随机推荐
- Mybatis框架基础入门(三)--Mapper动态代理方式开发
使用MyBatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper动态代理开发方法. 原始Dao开发方法需要程序员编写Dao接口和Dao实现类,此方式开发Dao,存在以下问题: Dao方 ...
- MyBatis 框架适用场合?
1.MyBatis 专注于 SQL 本身,是一个足够灵活的 DAO 层解决方案. 2.对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis 将是 不错的选择.
- Spring源码分析笔记--事务管理
核心类 InfrastructureAdvisorAutoProxyCreator 本质是一个后置处理器,和AOP的后置处理器类似,但比AOP的使用级别低.当开启AOP代理模式后,优先使用AOP的后置 ...
- 学习saltstack (七)
一.SaltStack概述 Salt,,一种全新的基础设施管理方式,部署轻松,在几分钟内可运行起来,扩展性好,很容易管理上万台服务器,速度够快,服务器之间秒级通讯. salt底层采用动态的连接总线, ...
- 学习zabbix(二)
超大规模门户网站集群架构: 运维30%的时间都在监控,监控要多维度: 监控(单机监控(系统监控).网络监控.应用监控.分布式监控): 业务监控(业务指标-->流量分析-->舆论监控): 流 ...
- PID算法原理 一图看懂PID的三个参数
找了好久这一篇算是很容易看懂的了 推荐给大家 写的十分清楚 原文作者DF创客社区virtualwiz LZ以前有个小小的理想,就是让手边的MCU自己"思考"起来,写出真正 ...
- 论文解读( N2N)《Node Representation Learning in Graph via Node-to-Neighbourhood Mutual Information Maximization》
论文信息 论文标题:Node Representation Learning in Graph via Node-to-Neighbourhood Mutual Information Maximiz ...
- [CSS]《CSS揭秘》第四章——视觉效果
投影 单侧投影 box-shadow:0px 10px 10px -5px black; 邻边投影 box-shadow:10px 10px 10px 2px black; 双侧投影 box-shad ...
- CSS揭秘之《多重边框》
1.box-shadow还接受第四个参数(称作"扩张半径"), 通过指定正值或负值, 可以让投影面积加大或者减小2.如果我们想要一道实线边框其实也是可以通过box-shadow来模 ...
- Nuxt.js服务端渲染实践,从开发到部署
感悟 经过几个周六周日的尝试,终于解决了服务端渲染中的常见问题,当SEO不在是问题的时候,或许才是我们搞前端的真正的春天,其中也遇到了一些小坑,Nuxt.js官方还是很给力的,提issue后很积极的给 ...