javaweb学习笔记(三):Servlet

版权声明:转载请注明出处: https://blog.csdn.net/qq_34774655/article/details/83152079

Servlet详解

1.Servlet概述与运行过程

由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。
<servlet>元素用于注册Servlet,它包含有两个主要的子元素:<servlet-name><servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名。

一个<servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:<servlet-name><url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。

<web-app>
	<servlet>
		<servlet-name>AnyName</servlet-name>
		<servlet-class>HelloServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>AnyName</servlet>
		<url-pattern>/demo/hello</url-pattern>
	</servlet-mapping>
</web-app>

Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
  ①Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
  ②装载并创建该Servlet的一个实例对象。
  ③调用Servlet实例对象的init()方法。
  ④创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
  ⑤WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。

2.Servlet映射路径

  1. url-pattern要么以 / 开头,要么以*开头。
  2. 不能同时使用两种模糊匹配(/**.do),例如/hello/*.do是非法路径
  3. 当有输入的URL有多个servlet同时被匹配的情况下:
    3.1 精确匹配优先。
    3.2 以后缀名结尾的模糊url-pattern优先级最低!!!(/*高于*.do)

关于缺省路径:
servlet的缺省路径(<url-pattern>/</url-pattern>)是在tomcat服务器内置的一个路径。该路径对应的是一个DefaultServlet(缺省Servlet)。这个缺省的Servlet的作用是用于解析web应用的静态资源文件。
URL输入http://localhost:8080/Test/index.html
1)到当前Test应用下的web.xml文件查找是否有匹配的url-pattern。
2)如果没有匹配的url-pattern,则交给tomcat的内置的DefaultServlet处理
3)DefaultServlet程序到Test应用的根目录下查找是存在一个名称为index.html的静态文件。
4)若找到该文件,则读取该文件内容,返回给浏览器;如果找不到,则返回404错误页面。

结论: 先找动态资源,再找静态资源。

3.Servlet 的生命周期

3.1生命周期方法

Servlet程序的生命周期由tomcat服务器控制!!
Servlet重要的4个生命周期方法:

  • 构造方法: 创建servlet对象的时候调用。默认情况下,第一次访问servlet的时 候创建servlet对象。只调用1次。证明servlet对象在tomcat是单实例的。
  • init方法(带参): 创建完servlet对象的时候调用。只调用1次。
  • service方法: 每次发出请求时调用。调用n次。
  • destroy方法: 销毁servlet对象的时候调用。停止服务器或者重新部署web应用 时销毁servlet对象。只调用1次。

注:①带参的init方法,是servlet的生命周期方法,一定会被tomcat服务器调用,且其会默认调用无参的init方法。一般不重写。
②若要编写初始化代码,需覆盖无参的init方法,在里面编写即可。

3.2伪代码演示生命周期

  1. 通过映射找到servlet-class的内容,字符串:gz.a_servlet.FirstServlet
  2. 通过反射构造FirstServlet对象
    2.1 得到字节码对象
    Class clazz = class.forName(“gz.itcast.a_servlet.FirstServlet”);
    2.2 调用无参数的构造方法来构造对象
    Object obj = clazz.newInstance(); servlet的构造方法被调用
  3. 创建ServletConfig对象,通过反射调用init方法
    3.1得到方法对象
    Method m = clazz.getDeclareMethod(“init”,ServletConfig.class);
    3.2 调用方法
    m.invoke(obj,config); servlet的init带参方法被调用
  4. 创建request,response对象,通过反射调用service方法
    4.1 得到方法对象
    Methodm m=clazz.getDeclareMethod(“service”,HttpServletRequest.class,HttpServletResponse.class);
    4.2 调用方法
    m.invoke(obj,request,response); servlet的service方法被调用
  5. 当tomcat服务器停止或web应用重新部署,通过反射调用destroy方法
    5.1 得到方法对象
    Method m = clazz.getDeclareMethod(“destroy”,null);
    5.2 调用方法
    m.invoke(obj,null); servlet的destroy方法被调用

4.自动加载

默认情况下,第一次访问servlet时创建servlet对象。如果servlet的构造方法或init方法中执行了比较多的逻辑代码,那么用户第一次访问sevrlet的时候比较慢。解决办法就是改变servlet创建对象的时机:提前到加载web应用的时候(tomcat启动时)!
在servlet的配置信息中,加上一个即可!注:整数值越大,创建的优先级越低。

<servlet>
    <servlet-name>LifeDemo</servlet-name>
    <servlet-class>gz.c_life.LifeDemo</servlet-class>
    <!-- 让servlet对象自动加载 -->
    <load-on-startup>1</load-on-startup> 
  </servlet>

如果WEB应用启动时就需要启动某个框架程序,那么可以把框架程序的启动代码放到一个Servlet的init方法中,并为这个Servlet配置</load-on-startup>。这样的话,当WEB应用启动时,框架也将随之启动。例如struts框架采用的就是这种启动方式。

5.并发问题

servlet对象在tomcat服务器是单实例多线程的。

因为servlet是多线程的,所以当多个servlet的线程同时访问了servlet的共享数据,如成员变量,可能会引发线程安全问题。

解决办法:把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步),建议在servlet类中尽量不要使用成员变量。如果确实要使用成员,必须同步。而且尽量缩小同步代码块的范围。以避免因为同步而导致并发效率降低。

6.ServletConfig对象

主要是用于加载servlet的初始化参数。在一个web应用可以存在多个ServletConfig对象(一个Servlet对应一个ServletConfig对象)。创建时机为在创建完servlet对象之后,在调用init方法之前。获得对象的途径为直接从有参数的init方法中得到。
servlet的初始化参数在servlet中配置, 这些参数会在加载web应用的时候(启动tomcat服务器),封装到ServletConfig对象中。
注: servlet的参数只能由当前的这个sevlet获取!

  <servlet>
    <servlet-name>ConfigDemo</servlet-name>
    <servlet-class>gz.f_config.ConfigDemo</servlet-class>
    <!-- 初始参数: -->
    <init-param>
    	<param-name>path</param-name>
    	<param-value>e:/b.txt</param-value>
    </init-param>
  </servlet>

ServletConfig的API:

java.lang.String 		 getInitParameter(java.lang.String name) 根据参数名获取参数值
java.util.Enumeration 	 getInitParameterNames()    获取所有参数名
ServletContext 			 getServletContext()        得到servletContex对象
java.lang.String 		 getServletName()           得到servlet的名称

7. ServletContext对象

ServletContext对象 ,叫做Servlet的上下文对象。表示一个当前的web应用环境。一个web应用中只有一个ServletContext对象。创建时机为在加载web应用时创建ServletContext对象。获得对象的途径为从ServletConfig对象的getServletContext方法得到。

<web-app>
	<!-- 在web-app之下配置web应用参数 -->
	<context-param>
		<param-name>AAA</param-name>
		<param-value>AAA's value</param-value>
	</context-param>
	<context-param>
		<param-name>BBB</param-name>
		<param-value>BBB's value</param-value>
	</context-param>

	<servlet>......</servlet>

	<servlet-mapping>...... </servlet-mapping>
</web-app>			

ServletContext对象的核心API(作用)

  • 得到当前web应用的路径,用在请求重定向的资源文件中。
    java.lang.String getContextPath()
  • web应用的初始化参数,可以让当前web应用的所有servlet获取!
    java.lang.String getInitParameter(java.lang.String name) java.util.Enumeration getInitParameterNames()
  • 域对象的作用是保存数据,获取数据。可以在不同的动态资源之间共享数据。
    四个域对象:
HttpServletRequet 				
ServletContext	:在整个web应用中有效
HttpSession 
PageContext

方法有:

void 					setAttribute(java.lang.String name, java.lan g.Object object)
java.lang.Object 		getAttribute(java.lang.String name)  
void 					removeAttribute(java.lang.String name)  
  • 转发:如果要使用HttpServletRequest域对象进行数据共享,只能用转发技术。
    转发与重定向的区别:
    a)转发的地址栏不会改变;而重定向地址栏会改变,变成重定向到的地址。
    b)转发只能转发到当前web应用内的资源;重定向可以跳转到当前web应用,或其他web应用,甚至是外部域名网站。
    c)可以在转发过程中,把数据保存到HttpServletRequest域对象中;而不可以在重定向过程中,把数据保存到HttpServletRequest域对象中。
    RequestDispatcher getRequestDispatcher(java.lang.String path)

转发:一个web资源收到客户端请求后,通知服务器去调用另外一个web资源进行处理。
重定向:一个web资源收到客户端请求后,通知浏览器去访问另外一个web资源。
区别:
RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件;而HttpServletResponse.sendRedirect 方法还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。

如果传递给HttpServletResponse.sendRedirect 方法的相对URL以“/”开头,它是相对于整个WEB站点的根目录;如果创建RequestDispatcher对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录。

调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL;调用RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。

HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求;RequestDispatcher.forward方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。

RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同一个访问请求和响应过程;而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和response对象,它们属于两个独立的访问请求和响应过程。

  • 得到web应用的资源文件
java.lang.String 			getRealPath(java.lang.String path) 
java.io.InputStream 		getResourceAsStream(java.lang.String path) 

猜你喜欢

转载自blog.csdn.net/qq_34774655/article/details/83152079
今日推荐