Servlet的详细解读目录
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映射路径
- url-pattern要么以 / 开头,要么以
*
开头。 - 不能同时使用两种模糊匹配(
/*
和*.do
),例如/hello/*.do
是非法路径 - 当有输入的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伪代码演示生命周期
- 通过映射找到servlet-class的内容,字符串:gz.a_servlet.FirstServlet
- 通过反射构造FirstServlet对象
2.1 得到字节码对象
Class clazz = class.forName(“gz.itcast.a_servlet.FirstServlet”);
2.2 调用无参数的构造方法来构造对象
Object obj = clazz.newInstance(); servlet的构造方法被调用 - 创建ServletConfig对象,通过反射调用init方法
3.1得到方法对象
Method m = clazz.getDeclareMethod(“init”,ServletConfig.class);
3.2 调用方法
m.invoke(obj,config); servlet的init带参方法被调用 - 创建request,response对象,通过反射调用service方法
4.1 得到方法对象
Methodm m=clazz.getDeclareMethod(“service”,HttpServletRequest.class,HttpServletResponse.class);
4.2 调用方法
m.invoke(obj,request,response); servlet的service方法被调用 - 当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)