Servlet学习笔记3——Servlet本质和生命周期

Servlet对象

Servlet的本质是什么?

Servlet是服务器端的小java程序,这个小java程序不能随意编写,必须实现SUN制定的javax.servlet.Servlet接口,实现其中的方法。Servlet是一个满足java规范的java类。Servlet既然满足Servlet规范,Tomcat服务器我们可以叫做“WEB容器(Container)”,那么Servlet 就可以叫做容器中的“组件(Component)”

Servlet对象的生命周期是什么样的,什么时候创建,创建几次,什么时候销毁?

假设客户端向web服务器发送的请求是/login请求,当用户向web服务器第一次发送/login请求的时候,Tomcat在容器中搜索/login对象的Servlet对象,但是没有找到该对象,此时会从web.xml文件中获取/login对象的完整Servlet类名,通过反射机制,调用Servlet的无参数构造方法创建Servlet对象,马上调用init方法完成Servlet对象的初始化操作,然后调用service方法提供核心服务。
当用户第2+次再发送/login请求的时候,Tomcat还是在容器中搜索/login对象的Servlet对象,此时可以找到该对象,直接调用该对象的service方法提供核心服务。
当用户长时间没有访问该Servlet,或者服务器关闭,或者项目重新部署的时候,Tomcat容器会去回收Servlet对象所占用的内存,在回收该内存之前调用该Servlet对象的destroy方法,完成回收之前的准备。

结论:
Servlet对象只创建一次(构造函数只执行一次)
Servlet对象的init方法在对象创建之后马上执行(只执行一次完成初始化操作)
Servlet对象service方法,只要用户访问一次则执行一次。
Servlet对象的destroy方法,也是只执行一次,执行之前对象没有销毁,即将销毁。

Servlet对象的生命周期由Tomcat容器管理,对象的创建,对象内存的释放,还有对象中的方法调用都是由Tomcat容器完成,程序员不能干涉,只能编写该类实现Servlet接口,将其配置在web.xml文件中。

Servlet对象是单实例的,并且是在多线程的环境下运行,可能存在线程并发带来的安全问题。

什么情况下在init方法中编写程序?什么情况下在service方法中编写程序?什么情况下在destroy方法中编写程序?

  • init方法是SUN规范中为程序员提供的一个对象初始化时机,这是一个特定的时刻,有的时候我们需要在这个特定的时刻执行一段特定的程序,此时将该程序写入init方法,例如:项目经理要求在Servlet对象创建时刻记录日志,请将该程序编写到init方法中。对象第一次创建的时候执行记录日志,并且只执行一次,记录一次日志信息。(init方法一般很少用)
  • Service方法是Servlet的核心业务方法,核心业务都在该方法中完成,只要编写一个Servlet,service方法是一定要编写代码的,完成业务的处理。(常用)
  • destroy方法init方法相同,只不过是一个不同的时机。(destroy方法一般很少使用)

研究Servlet对象的生命周期

​ 1、在myeclipse中设置文件的默认打开方式:
​ Window–>Preferences–>file associations–>找到对应扩展名选项–>设置默认打开方式default

​ 2、什么是Servlet生命周期?
​ Servlet对象的生命周期表示:Servlet对象从最初的创建,到最终的销毁,经历了哪些不同的过程。

​ 3、Servlet对象的创建,Servlet对象的方法被调用,Servlet对象的销毁,都是由WEB容器来负责管理的,
​ javaweb程序员是不需要管理这些的。
​ javaweb程序员主要负责:
​ Servlet类的编写,
​ service方法的实现,
​ Servlet类在web.xml文件中的配置。

​ 4、myeclipse快捷键:
​ alt + / 自动补全
​ ctrl + 1 纠错
​ ctrl + o 查看类的属性和方法
​ ctrl + shift + t 查找类
​ ctrl + shift + o 组织导入
​ ctrl + / 注释和取消注释
​ tab 缩进
​ shift + tab 取消缩进
​ ctrl + shift + f 格式化【不建议使用】
​ ctrl + alt + 向下箭头 复制一行
​ ctrl + z 撤销
​ ctrl + y 重做
​ ctrl + s 时刻记住这个“保存”
​ ctrl + c
​ ctrl + x
​ ctrl + v
​ ctrl + d 删除光标所在行

​ 5、web.xml文件在服务器启动阶段被解析,若web.xml文件编写有错误,启动Tomcat服务器的时候,当前webapp启动失败。

​ 6、Servlet对象“默认情况”下,在服务器启动阶段是不会实例化的。不会创建对象

​ 7、Servlet对象的生命周期
​ 1) 用户打开浏览器在浏览器地址栏上输入URL:http://localhost:8080/oa/save,回车
​ 2) WEB服务器截取请求路径,得知用户要访问的资源是:/oa/save
​ 3) WEB服务器从整个容器中检索/oa/save请求路径对应的Servlet对象
​ 4) 若找到了该Servlet对象
​ 4-1) web容器负责调用该Servlet对象的service方法提供服务,处理请求
​ 5) 若没有找到该Servlet对象
​ 5-1) 通过请求路径/save找到对应的Servlet完整类名(web.xml文件支持的,web.xml文件在服务器启动阶段解析,路径和类名已经绑定在一起了)
​ 5-2) 通过反射机制调用Servlet类的无参数构造方法完成Servlet对象的实例化操作。(Servlet对象已经创建完毕)
​ 5-3) web容器调用该Servlet对象的init方法完成初始化操作。
​ 5-4) web容器调用该Servlet对象的service方法提供服务,处理请求
​ 6) 若“服务器关闭”或“webapp重新部署”或“长时间没有用户再访问该Servlet”,WEB容器
​ 会销毁该Servlet对象占用的内存空间,web容器在销毁该Servlet对象之前,web容器负责
​ 调用该Servlet对象的destroy方法,完成销毁之前的准备工作。

​ 8、Servlet对象是单实例的,不符合单例模式,是一种伪单例,真单例的构造方法必须是私有化的。
​ Servlet对象是在多线程环境下运行的一个对象。【单实例多线程环境下运行的一个java对象】
​ 之所以Servlet对象是单实例的,是因为该对象的创建是由WEB容器负责的,javaweb程序员不能干涉

​ 9、单例分类:

​ 真单例

​ 伪单例

10、总结:
1) 无参数构造方法只调用一次,对象只创建一个,对象是单例的
2) init方法只被调用一次,在对象创建之后马上执行它,完成初始化操作
3) service方法,只要用户发送请求一次,则执行一次
4) destroy方法也是只执行一次
注意:
init方法在执行的时候,对象已经存在了。
destroy方法在执行的时候,对象还没有被回收,还存在。

11、分析Servlet中重要的三个方法:
init
service
destroy

问题:你觉得哪个方法使用最多?  
		service方法,因为在这个方法中需要提供服务,处理当前的请求,这是核心方法,用户访问的每一次都是要执行的。
		
问题:你觉得init方法和destroy,SUN公司为什么在Servlet接口中设计这两个方法,这两个方法什么时候使用?
		其实init、destroy方法都是SUN公司为javaweb程序员准备的特殊的时刻,初始化时刻/销毁时刻
		一般这两个方法中是不需要编写任何代码的,但是在特殊的情况下,例如:需求要求在对象被初始化
		的那一刻记录日志,那么记录日志的代码就编写到init方法中,例如:需求要求在该Servlet对象
		被销毁的那一刻记录日志,那么记录日志的代码就需要编写到destroy方法。自然会被服务器调用
		并执行。

12、重点:
在Servlet类中最好不要手动编写任何构造函数,这样做可能会导致无参数构造函数不存在,
这样通过反射机制创建对象的时候,会出现实例化异常。Servlet对象创建失败。

13、错误代号:【HTTP状态号】
404 - 资源找不到,通常是路径问题,还有可能是项目本身启动失败
500 - 服务器内部错误,通常是服务器中的java程序出现了异常。

研究服务器启动阶段怎么实例化Servlet对象呢?

​ 在web.xml文件的标签内部添加:1
​ 该标签表示在服务器启动阶段加载Servlet,完成实例化和初始化。
​ 数字越小,优先级越高。

关于一个web站点的欢迎页面的设置

​ 1、设置欢迎页面的作用:
​ 在访问该web站点的时候,没有提供任何资源路径,直接访问的是该web站点的欢迎页面
​ 若欢迎页面没有进行相关的设置,会出现404
​ 例如:访问 http://localhost:8080/prj-servlet-04/
​ 直接跳转到欢迎页面,但是没有设置欢迎页面的时候,出现404错误

​ 2、当修改web.xml文件的时候,保存之后,Tomcat服务器会自动重新解析web.xml文件,
​ 这个时候,就相当于项目重新部署了。

​ 2、怎么设置欢迎页面?
​ 修改web.xml文件:

		<welcome-file-list>
			<welcome-file>login.html</welcome-file>
			<welcome-file>save.html</welcome-file>
			<welcome-file>welcome.html</welcome-file>
			<welcome-file>html/welcome.html</welcome-file>
		</welcome-file-list>

​ 注意:
​ 欢迎页面可以设置多个,第一个优先级最高,以此类推
​ 欢迎页面路径问题:不需要以“/”开始,但是从WebRoot作为起点

​ 3、欢迎页面必须是一个HTML吗?可以是Servlet吗?
​ 欢迎页面也可以是一个Servlet
​ 例如:

		<servlet>
			<servlet-name>deleteServlet</servlet-name>
			<servlet-class>com.bjpowernode.javaweb.servlet.DeleteServlet</servlet-class>
		</servlet>
		<servlet-mapping>
			<servlet-name>deleteServlet</servlet-name>
			<url-pattern>/user/delete</url-pattern>
		</servlet-mapping>
		<welcome-file-list>
			<welcome-file>user/delete</welcome-file>
		</welcome-file-list>

​ 4、当前web站点没有设置任何欢迎页面的话,欢迎页面是:index.html、index.htm、index.jsp
​ 这是怎么回事?
​ 是因为在CATALINA_HOME/conf/web.xml文件中有全局配置:

<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

在当前webapp中配置的欢迎页面属于局部配置,局部优先(就近原则)
ServletConfig对象详解

l javax.servlet.ServletConfig是SUN制定的接口,apache对ServletConfig接口的实现类的完整类名是:org.apache.catalina.core.StandardWrapperFacade,但是作为程序员不需要关心具体的类型,只要面向javax.servlet.ServletConfig接口调用即可,程序运行阶段执行的是apache的ServletConfig的实现类中的方法。

l Servlet****对象的创建以及方法的调用过程

Class c = Class.forName("com.bjpowernode.javaweb.servlet.ServletConfigTest");
Servlet servlet = (Servlet)c.newInstance();
ServletConfig config = new org.apache.catalina.core.StandardWrapperFacade();
servlet.init(config);
ServletRequest request = 创建了apache的一个request对象;
ServletResponse response = 创建了apache的一个response对象;
servlet.service(request,response);
servlet.service(request,response);
servlet.service(request,response);
servlet.service(request,response);
………………
servlet.destroy();

Servlet和ServletConfig之间的关系?
一个Servlet对象会对应一个ServletConfig对象。
ServletConfig对象的本质是什么?
ServletConfig实际上是一个Servlet对象相关的配置信息对象。一个Servlet在web.xml文件中标签中配置的信息会自动被封装到ServletConfig对象中,通过ServletConfig对象我们可以获取到当前的Servlet对象的相关配置信息。
ServletConfig接口中常用的方法
通过初始化参数的name获取初始化参数的value
String value = config.getInitParameter(String name);
获取所有初始化参数的name
Enumeration names = config.getInitParameterNames();
获取ServletContext对象
ServletContext application = config.getServletContext();

研究javax.servlet.ServletConfig接口:

1、javax.servlet.ServletConfig是接口

2、apache Tomcat服务器对ServletConfig接口的实现类完整类名是:
	org.apache.catalina.core.StandardWrapperFacade
	
	public class org.apache.catalina.core.StandardWrapperFacade 
		implements javax.servlet.ServletConfig{
	
	}
	
	注意:
		对于javaweb程序员来说,我们不需要关心ServletConfig接口的实现类是什么!!!!
		我们只需要面向ServletConfig接口调用即可。
		这就是面向接口编程
		ServletConfig接口的调用者:javaweb程序员
		ServletConfig接口的实现者:web容器/web服务器/Tomcat服务器
		
		Tomcat容器实现了Servlet+JSP规范。

3、ServletConfig对象中保存了什么信息?ServletConfig是干什么的?
	ServletConfig对象是“Servlet对象的配置信息对象”
	Servlet对象的配置信息在web.xml文件中的<servlet></servlet>标签内部
	ServletConfig对象封装了当前Servlet对象的配置信息。
	通过ServletConfig对象可以获取该Servlet对象的相关配置信息。

4、一个Servlet对象对应一个ServletConfig对象,100个Servlet对象对应100个ServletConfig对象。

5、ServletConfig接口中常用方法有哪些?
  • String getInitParameter(String name) 通过初始化参数的name获取value
  • Enumeration getInitParameterNames() 获取所有初始化参数的name
  • ServletContext getServletContext() 获取ServletContext对象【ServletContext后面讲】
  • String getServletName() 【使用较少】

ServletConfig在init方法中,怎么样能在service方法中使用ServletConfig呢?
1、提供一个实例变量:private ServletConfig config;
2、在init方法中编写:this.config = config;
3、实现getServletConfig方法,直接返回:config

ServletContext对象详解
javax.servlet.ServletContext是SUN制定的接口,apache对ServletContext接口的实现类完整类名:org.apache.catalina.core.ApplicationContextFacade,但是程序员不需要关心具体的类名,直接面向ServletContext接口调用方法即可。
如何获取ServletContext对象呢?
通过ServletConfig对象获取ServletContext对象
ServletContext application = config.getServletContext();
ServletContext代表什么?什么时候被创建?什么时候被销毁?
ServletContext在Tomcat服务器启动阶段解析webapp中的web.xml文件的时候创建ServletContext对象。
在Tomcat服务器关闭的时候ServletContext对象被销毁。
对于同一个webapp来说,ServletContext对象只有一个。
ServletContext代表“Servlet上下文”。ServletContext上下文指的是“所有Servlet对象共享的一个四周环境”对象。在同一个WEBAPP中,所有的Servlet对象共享一个ServletContext对象。存储在ServletContext对象中的数据所有的Servlet共享。ServletContext对象可以完成多个Servlet之间数据的传递。
ServletContext接口中常用的方法
向Servlet上下文中存储数据
application.setAttribute(String name,Object obj);
从Servlet上下文中读取数据
Object obj = application.getAttribute(String name);
删除Servlet上下文中的数据
application.removeAttribute(String name);
获取Servlet上下文参数所有的name
Enumeration names = application.getInitParameterNames();
通过Servlet上下文参数的name获取value
String value = application.getInitParameter(String name);
通过ServletContext获取文件的绝对路径真实路径
String realPath = application.getRealPath(“/index.html”); 注意:必须保证webapp的根下有index.html
什么样的数据适合存储到ServletContext对象中?
很少的数据量
所有用户共享的数据
这些共享数据不涉及到修改操作,或者很少涉及到修改操作。
多线程环境下,什么情况下需要考虑线程并发带来的安全问题?
多线程环境下运行程序
有共享的数据
共享数据涉及到修改操作
解决线程安全问题有两种解决方案?
使用局部变量替代成员变量、静态变量,局部变量在栈中存储,栈内存不共享,成员变量在堆内存的java对象内部存储,堆内存是共享的,静态变量在方法区中存储,方法区内存也是多线程共享的。
使用线程同步机制:synchronized语法支持线程同步机制。(会使并发量降低,吞吐量降低)

研究javax.servlet.ServletContext接口

​ 1、javax.servlet.ServletContext是一个接口

​ 2、apache Tomcat服务器对ServletContext接口的实现,实现类的完整类名:org.apache.catalina.core.ApplicationContextFacade
​ public class org.apache.catalina.core.ApplicationContextFacade implements javax.servlet.ServletContext{

​ }
​ 注意:javaweb程序员不需要关心具体的实现类,还是面向ServletContext接口调用方法即可。实现类是服务器负责的。
​ Tomcat就是一个实现了Servlet+JSP规范的容器。

​ 3、ServletContext对象的个数?
​ 在同一个webapp中,ServletContext对象只有一个
​ 在web服务器启动阶段被创建
​ 在web服务器关闭的时候被销毁
​ ServletContext对象是一个应用级别的对象。
​ 注:100个app对应100个ServletContext

​ 一个Servlet对应一个ServletConfig,所有的Servlet共享一个ServletContext

​ 4、ServletContext怎么理解,它是什么,主要作用是什么?

  • ServletContext是一个Servlet上下文对象

  • ServletContext对象是所有Servlet共享的一个四周环境对象

    • Context单词翻译:上下文
    • 例如:contextPath就是上下文路径: /prj-servlet-06 【webapp的根路径】
    • ServletContext可以完成多个Servlet之间共享同一些数据。
    • ServletContext对象中封装了web.xml文件中所有信息,
      ServletContext对象只有一个,web.xml文件也是只有一个
      web.xml文件也是在服务器启动阶段被解析,ServletContext也是在服务器启动阶段被创建。

5、ServletContext接口中常用的方法:

void setAttribute(String name, Object object) //向Servlet上下文中绑定一个数据object,起名name (map.put(key,value))

Object getAttribute(String name) //从Servlet上下文中取object,通过name (Object value = map.get(key))

void removeAttribute(String name) //移除Servlet上下文中的某个数据,通过name (map.remove(key))

String getInitParameter(String name) //通过上下文参数的name获取上下文参数value

Enumeration getInitParameterNames() //获取所有上下文参数的name

String getRealPath(String path) //获取绝对路径

InputStream getResourceAsStream(String path) //直接获取文件输入流

6、通过ServletContext对象可以完成:跨用户传递数据

Servlet、ServletConfig、ServletContext对象的内存关系

Servlet、ServletConfig、ServletContext三个对象的代码关系如下所示:
public class Servlet{
private ServletConfig config;
public ServletConfig getServletConfig(){
return config;
}
}
public class ServletConfig{
private ServletContext servletContext;
public ServletContext getServletContext(){
return servletContext;
}
}
Servlet、ServletConfig、ServletContext三个对象内存关系图:

在这里插入图片描述

结论:一个Servlet对应一个ServletConfig对象,所有的Servlet对象共享一个ServletContext对象。

猜你喜欢

转载自blog.csdn.net/kilotwo/article/details/114155520