---- 概念

Servlet是一种服务器端的Java应用程序,具有独立于平台和协议的特性,可以生成动态的Web页面。 它担当客户请求(Web浏览器或其他HTTP客户程序)与服务器响应(HTTP服务器上的数据库或应用程序)的中间层。 Servlet是位于Web 服务器内部的服务器端的Java应用程序,与传统的从命令行启动的Java应用程序不同,Servlet由Web服务器进行加载,该Web服务器必须包含支持Servlet的Java虚拟机。

Servlet 容器是 web server 或 application server 的一部分,提供基于请求/响应发送模型的网络服务,解码基于 MIME 的请求,并且格式化基于 MIME 的响应。Servlet 容器也包含了管理 Servlet 生命周期。

   附加文中参考代码

---- 生命周期

说明:

    init():
在Servlet的生命周期中,仅执行一次init()方法。它是在服务器装入Servlet时执行的,负责初始化Servlet对象。可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行init()。
   service():
它是Servlet的核心,负责响应客户的请求。每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。
   destroy():
仅执行一次,在服务器端停止且卸载Servlet时执行该方法。当Servlet对象退出生命周期时,负责释放占用的资源。一个Servlet在运行service()方法时可能会产生其他的线程,因此需要确认在调用destroy()方法时,这些线程已经终止或完成。

Servlet在Tomcat的工作流程

说明:

   1)web client向Tomcat发起Http请求

   2)Servlet容器接收到该Http请求

   3)Servelt容器创建一个HttpRequest对象,将web client的请求信息封装到这个对象中去

   4)Servelt容器创建一个HttpResponse对象

   5)Servelt容器调用HttpServlet对象中的service()方法,将HttpRequest对象和HttpResponse对象作为参数传给HttpServlet对象

   6)HttpServlet对象调用HttpRequest对象的相关方法,获取http请求信息

   7)HttpServlet对象调用HttpResponse对象的相关方法,返回响应数据

   8)Servlet容器把HttpServlet的响应结果传给Web Client

---- Servlet的对象

HttpServletRequest 请求对象:获取请求信息

HttpServletResponse 响应对象: 设置响应对象

ServletConfig对象: servlet配置对象

ServletContext对象: servlet的上下文对象

--- ServletConfig对象

1) 作用

主要是用于加载servlet的初始化参数。在一个web应用可以存在多个ServletConfig对象(一个Servlet对应一个ServletConfig对象)

2)创建

在创建完servlet对象之后,在调用init方法之前创建,直接从有参数的init方法中得到

3)举个栗子

servlet文件

//ServletConfig用于封装servlet的配置
public class ServletDemo1 extends HttpServlet { private ServletConfig config;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//返回此上下文中支持servlet API级别的最大和最小版本号
int m = this.getServletContext().getMinorVersion();
int n = this.getServletContext().getMajorVersion();
System.out.println("m="+m+",n="+n); System.out.println(this.getServletConfig().getServletName());
System.out.println(this.getServletConfig().getInitParameter("data")); //得到所有的值
Enumeration<String> initParameterNames = getServletConfig().getInitParameterNames();
while(initParameterNames.hasMoreElements()){
String name = initParameterNames.nextElement();
System.out.println(name);
System.out.println(this.getServletConfig().getInitParameter(name));
}
} protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
} }

web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>ServletTest</display-name>
<servlet>
<servlet-name>ServletDemo1</servlet-name>
<servlet-class>com.xxg.web.ServletDemo1</servlet-class>
<init-param>
<param-name>data</param-name>
<param-value>xxxx</param-value>
</init-param>
<init-param>
<param-name>data2</param-name>
<param-value>yyyy</param-value>
</init-param>
</servlet> <servlet-mapping>
<servlet-name>ServletDemo1</servlet-name>
<url-pattern>/ServletDemo1</url-pattern>
</servlet-mapping>
</web-app>

运行结果:

说明:其实可以不用先获得ServletConfig,然后在获取其各种参数,可以直接使用其方法,比如上面我们用的ServletConfig().getServletName();可以直接写成getServletName();而不用在先获取ServletConfig();了,原因就是在GenericServlet中,已经帮我们获取了这些数据,我们只需要直接拿就行。

--- ServletContext对象

1)作用

ServletContext对象 ,叫做Servlet的上下文对象。tomcat为每个web项目都创建一个ServletContext实例,tomcat在启动时创建,服务器关闭时销毁,在一个web项目中共享数据,管理web项目资源,为整个web配置公共信息等,通俗点讲,就是一个web项目,就存在一个ServletContext实例,每个Servlet读可以访问到它。一个web应用中只有一 个ServletContext对象

2)创建

加载web应用时创建ServletContext对象,加载web应用时创建ServletContext对象

3)举个栗子

在上边的ServletDemo1文件中

    //在公共区域存放了一个key值为key1,value值为xiaomi的值
getServletContext().setAttribute("key1", "xiaomi");
String value = (String) this.getServletContext().getAttribute("key1");
System.out.println("key1: "+value);

在里面的一个ServletDemo2文件中

/*
ServletContext域:1,是一个容器 2。作用范围是应用程序范围
*/
/*@WebServlet("/ServletDemo2")*/
public class ServletDemo2 extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//在ServletDemo2通过ServletContext获取在ServletDemo1中设置的值
String value = (String) this.getServletContext().getAttribute("key1");
System.out.println("key1: "+value);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
} }

运行结果:(注意需要先运行ServletDemo1,让ServletContext区域存储值,再运行ServletDemo2)

--- 其他两个对象补充

1)请求转发

request.getRequestDispatcher(String path).forward(request,response);  //path:转发后跳转的页面,这里不管用不用"/"开头,都是以web项目根开始,因为这是请求转发,请求转发只局限与在同一个web项目下使用,所以这里一直都是从web项目根下开始的,

web项目根:

      开发:G:\Workspaces\test01\WebRoot\..

         运行时:D:\java\tomcat\apache-tomcat-7.0.53\webapps\test01\..

   web站点根:

      运行时:D:\java\tomcat\apache-tomcat-7.0.53\webapps\..

  从这里可以看出,web项目根就是从该web项目名开始,所以我们请求转发时,只需要接着项目名后面需要访问的路径写就行了,

  特点浏览器中url不会改变,也就是浏览器不知道服务器做了什么,是服务器帮我们跳转页面的,并且在转发后的页面,能够继续使用原先的request,因为是原先的request,所以request域中的属性都可以继续获取到。

2)重定向

方式一:手动方案

  response.setStatus(302);  //状态码302就代表重定向

  response.setHeader("location","http://www.baidu.com");

方式二:使用封装好的,通过response.sendRedirect("http://www.baidu.com");

  特点服务器告诉浏览器要跳转的页面,是浏览器主动去跳转的页面,浏览器知道,也浏览器的地址栏中url会变,是浏览器重新发起一个请求到另外一个页面,所以request是重新发起的,跟请求转发不一样。

  注意:response.sendRedirect(path);  //

  第一种:response.sendRedirect("/test01/MyServlet01");  //使用了"/"开头,说明是从web站点根开始,所以需要写test01/MyServlet01

  第二种:response.sendRedirect("MyServlet01");  //没有使用"/"开头,说明是从web项目根开始,那么就无需写test01了。

 重定向没有任何局限,可以重定向web项目内的任何路径,也可以访问别的web项目中的路径,并且这里就用"/"区分开来,如果使用了"/"开头,就说明我要重新开始定位了,不访问刚才的web项目,自己写项目名,如果没有使用"/"开始,那么就知道是访问刚才那个web项目下的servlet,就可以省略项目名了。就是这样来区别。

----Servlet与多线程

?-Servlet容器默认是采用单实例多线程的方式处理多个请求的

1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在一个Servlet实例);
2.容器初始化化Servlet主要就是读取配置文件(例如tomcat,可以通过servlet.xml的<Connector>设置线程池中线程数目,初始化线程池通过web.xml,初始化每个参数值等等。
3.当请求到达时,Servlet容器通过调度线程(Dispatchaer Thread) 调度它管理下线程池中等待执行的线程(Worker Thread)给请求者;
4.线程执行Servlet的service方法;
5.请求结束,放回线程池,等待被调用;
(注意:避免使用实例变量(成员变量),因为如果存在成员变量,可能发生多线程同时访问该资源时,都来操作它,照成数据的不一致,因此产生线程安全问题)

    从上面可以看出:

  第一:Servlet单实例,减少了产生servlet的开销;

    第二:通过线程池来响应多个请求,提高了请求的响应时间;

    第三:Servlet容器并不关心到达的Servlet请求访问的是否是同一个Servlet还是另一个Servlet,直接分配给它一个新的线程;如果是同一个Servlet的多个请求,那么Servlet的service方法将在多线程中并发的执行;

   第四:每一个请求由ServletRequest对象来接受请求,由ServletResponse对象来响应该请求;

?-Servlet如何处理多个请求访问

    servlet是默认采用单实例,多线程的方式进行。只要webapp被发布到web容器中的时候,servlet只会在发布的时候实例化一次,servlet在其生命周期中只有在将项目给移除或服务器stop的时候才会销毁,那么一个web项目从发布到运行只存在一个servlet的实例。

    当容器收到一个Servlet请求,调度线程从线程池中选出一个工作者线程,将请求传递给该工作者线程,然后由该线程来执行Servlet的service方法。当这个线程正在执行的时候,容器收到另外一个请求,调度线程同样从线程池中选出另一个工作者线程来服务新的请求,容器并不关心这个请求是否访问的是同一个Servlet.当容器同时收到对同一个Servlet的多个请求的时候,那么这个Servlet的service()方法将在多线程中并发执行。

   在Tomcat7.0.3中的server.xml里面的代码:

<!--The connectors can use a shared executor, you can define one or more named thread pools-->
<!--
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
--> <!--
<Connector executor="tomcatThreadPool"
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
-->

?-Servlet如何实现线程安全

1、实现 SingleThreadModel 接口 

     该接口指定了系统如何处理对同一个Servlet的调用。如果一个Servlet被这个接口指定,那么在这个Servlet中的service方法将不会有两个线程被同时执行,当然也就不存在线程安全的问题。(但是Servlet2.4中已不再提倡使用)

2、同步对共享数据的操作
使用synchronized 关键字能保证一次只有一个线程可以访问被保护的区段,但是在JMM内存模型中可以知道,使用synchronized为了保证主内存和工作内存一致性,会来回切换内核线程与用户线程,会造成一定的资源浪费,使得系统性能下降,所以在实际的开发中也应避免或最小化 Servlet 中的同步代码

、避免使用实例变量

    局部变量是在堆栈中运行。每个运行的线程都有自己的堆栈。
    别的线程无法访问得到,因此我们说,局部变量是“安全”的。
    全局变量在堆中,堆是对所有的线程都可见的。
   因此在两个以上的线程访问全局变量时,就会出现所谓的“不安全”,a线程访问全局变量,赋值为a,然后中间睡眠了0.001秒,在此期间b进程访问了全局变量,赋值为b了,此时a线程醒来了,抢了处理机制,发现全局变量是b,显然不是我们a线程所要到的值,这时就要加入同步机制或者定义为局部变量,比如如果是方法的话就加同步方法,代码块就加同步代码块。

举个栗子

public class Test1{
...
public void fun1(){
String s = "";
System.out.print(s);
}
} public class Test2{
...
String s ;
public void fun1(){
System.out.print(s);
}
}

说明:第一种Test1  如果Test1只有一个实例化对象,那么不同的用户访问他的话,每一个用户执行的fun1方法都是由自身的线程单独开辟的空间的。

第二种Test2 如果Test2只有一个实例化对象,那么不同的用户访问他的话,那每一个用户访问的s都是同一个变量,那么线程安全性就很难保证。所以建议第一种方法。

参考资料:Servlet其实是多线程

Servlet中的几个重要对象

说说Servlet 生命周期、工作原理

关于Servlet一些东西的更多相关文章

  1. javaWeb基础核心之一Servlet

    既然是做JAVA开发的,先从一些基本的整理起来,算是知识回顾,加深记忆. 第一篇想到那理到哪,可能有点乱,不是太会排版,见谅,估计可能也就我自己看的懂. servlet在百度百科上的定义是这样的: S ...

  2. 重温 JSP 与 Servlet

    Java Web使用SSH框架多了,很多基础的 JSP 与 Servlet 的东西都忘记了.最近在 JSP 标签 和 Struts2 包装的 Session 对象的混合使用时弄晕了,就翻书温习下. J ...

  3. servlet三大组件

    servlet大致可以分为三个:简单servlet.过滤servlet.监听servlet servlet: servlet的创建 创建一个类并实现Servlet接口. 重写service方法. 在服 ...

  4. freemarker:简介

    Apache FreeMarker模板引擎:Java库来生成文本输出(HTML网页,电子邮件,配置文件,源代码,等等)基于模板和变化的数据.模板都写在FreeMarker模板语言(FTL),这是一个简 ...

  5. java web学习

    一直想下决心好好学下java web,但是总是间断,虽然我的方向是ios,但是觉得后台也是相当重要,毕竟移动端实际上更多也就是展示后台拉取到的信息,搞移动端的不能总是受制于后台,各位看官觉得呢? 这两 ...

  6. 关于SSH框架设计的一些理解

    近期在学习企业开发领域非常流行的SSH框架(Struts.Hibernate.Spring).因为之前有做过原生的Servlet+JSP的项目,所以在学习过程中我会跟原生开发模式进行对照,在这里我把自 ...

  7. 调用支付宝第三方接口(沙箱环境) SpringMVC+Maven

    一.蚂蚁金服开放平台的操作 网址:https://open.alipay.com/platform/home.htm 支付宝扫码登陆

  8. tomcat是什么?Tomcat 下载、安装、配置图文教程

    你用浏览器上网的所有操作,所有请求发送给服务器(tomcat),服务器通过请求,找相应的逻辑处理程序(jsp或servelet或java类,就是有关java语言的所有可以处理逻辑的代码,其中包括访问后 ...

  9. Java中 Tomcat 是干什么的?

    Tomcat是web容器.它的作用稍后给你解释. 你在做web项目时,多数需要http协议,也就是基于请求和响应,比如你在百度输入一行内容搜索, 那么百度服务器如何处理这个请求呢,他需要创建servl ...

随机推荐

  1. poj2186【利用强连通分量】

    题意: 有n头奶牛,然后有个规则是A->B,B->C,那么A->C: A觉得B受欢迎,B觉得C受欢迎,那么A觉得C受欢迎: 求:被其他所有牛都欢迎的牛的数量: 思路: 原来的思路: ...

  2. spring3升级到spring4

    升级又失败了,dao层太多要改了,记录一下修改的内容,也是没白费我一下午时间 1. org.springframework.orm.hibernate3.annotation.AnnotationSe ...

  3. django接受表单

    from django.shortcuts import render from django.shortcuts import HttpResponse import os # Create you ...

  4. 165 Compare Version Numbers 比较版本号

    比较两个版本号 version1 和 version2.如果 version1 大于 version2 返回 1,如果 version1 小于 version2 返回 -1, 除此以外 返回 0.您可 ...

  5. Sublime3注册码和安装中文包

    1.Sublime3注册码 在工具栏Help中点击Enter license,粘贴下面一大串 —– BEGIN LICENSE —– Michael Barnes Single User Licens ...

  6. Python 版本对比

    python2 与 python3可认为代码不通用,你也可以点击Python2.x与3​​.x版本区别来查看两者的不同 python3.6以上支持f-string,一种很方便的变量替换方式 高版本可能 ...

  7. AJPFX谈JAVA新手问题之异常处理使用不当

    ★空的 catch 语句块 犯这种错误的人比较少,一般发生在刚学会 Java 或者刚参加工作不久的人身上. 所谓“空 catch 语句块”就是在 catch 语句块中没有对异常作任何处理(比如记错误日 ...

  8. re正则表达式公式讲解5

    1.refullmatch() 完全匹配字符串则返回object,否则返回None import re s = "max@123uyt146" print(re.fullmatch ...

  9. VS2013编译libjpeg库

    第一步:找到刚刚解压出来的“jpeg-9a”文件夹下面的“makefile.vc”文件,用记事本或Notepad++等编辑工具打开,然后找到里面的“!include <win32.mak> ...

  10. 将vue-cli项目配置在nginx上

    登录使用的是node.js搭建的注册登录接口,关于对数据库的读写则是用spring boot的框架来实现的. 1.首先是vue-cli项目里的前端页面的配置: location / { root    ...