Servlet的一些细节问题
Servlet的细节问题
1.一个已经注册的Servlet可以被多次映射即:
<servlet> <!-- servlet的注册名 --> <servlet-name>MyServlet1</servlet-name> <!-- servlet类的全路径(包名+类名) --> <servlet-class>com.hsp.servlet.MyServlet1</servlet-class> </servlet> <!-- 对一个已经注册的servlet的映射 --> <servlet-mapping> <!-- servelt的注册名 --> <servlet-name>MyServlet1</servlet-name> <!-- servlet的访问路径 --> <url-pattern>/MyServlet1</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>MyServlet1</servlet-name> <url-pattern>/winner</url-pattern> </servlet-mapping>
2.当映射一个servlet时候,可以多层 比如
<url-pattern>/servlet/index.html</url-pattern> ok
从这里还可以看出,后缀名是html不一定就是html,可能是假象.
3.把servlet映射到URL中时可以使用*通配符,但是只能有两种方式。
有两种格式:
第一种格式 *.扩展名 比如 *.do,*.ss
第二种格式 以/开头,同时以 /* 结尾.比如/*(所有的请求都跳转到某个地方,如要把整个网站关闭)
/news/*(我们要把门户网站的新闻频道关闭,,所有对新闻频道的访问都跳转到某个页面)
通配符练习题:
Servlet1 映射到 /abc/*
Servlet2 映射到 /*
Servlet3 映射到 /abc
Servlet4 映射到 *.do
问题(面试题):
当请求URL为"/abc/a.html","/abc/*"和"/*"都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
当请求URL为"/abc"时,"/abc/*"和"/abc"都匹配,哪个servlet响应
Servlet引擎将调用Servlet3。
当请求URL为"/abc/a.do"时,"/abc/*"和"*.do"都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
当请求URL为"/a.do"时,"/*"和"*.do"都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
当请求URL为"/xxx/yyy/a.do"时,"/*"和"*.do"都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
在匹配的时候,要参考的标准:
(1)看谁的匹配度高,谁就被选择
(2)*.do 的优先级最低
实际应用:现在我们要把整个网站关闭,我们自己写一个servlet,如CloseServlet,向页面输出out.println(‘对不起,该网站暂时关闭’)。然后配置web.xml:
<servlet> <servlet-name>CloseServlet</servlet-name> <servlet-class>com.....CloseServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>CloseServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
对这个网站的所有请求都由CloseServlet处理。
将原来web.xml拷贝一份,重命名为web.xml.bak,网站恢复之后再改回来!
4.Servlet单例问题
针对客户端的多次servlet请求,通常情况下,服务器只会创建一个servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其他请求服务,直至web容器退出或者reload该web应用,servlet实例才会销毁。
在servlet的整个生命周期中,servlet的init()方法只会被调用一次,而对一个servlet的每次访问请求都会导致servlet引擎调用一次servlet实例的service()方法,对于每次访问请求,servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给他调用的servlet的service()方法,service方法再根据请求方式分别调用doXXX方法。
当Servlet被第一次访问后,就被加载到内存,以后该实例对各个请求服务.即在使用中是单例.
因为Servlet是单例,因此会出现线程安全问题: 比如:售票系统. 如果不加同步机制,则会出现问题:
怎么证明是单例呢?
public class MyServlet1 extends HttpServlet { int i = 0; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { i++; response.getWriter().println("hello, i="+i); } }
i的值会一直增加!多个请求增加的是同一个i。
售票可能出现的问题:
public class MyServlet1 extends HttpServlet { int ticket = 2; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if(ticket > 0){ System.out.println("你买到票了"); try { //线程休眠用来模拟成千上万个人同时并发,因为一个售票系统会有很多人同时访问! Thread.sleep(10 * 1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //先休眠再减!!买完票还没来得及减另一个人就来买了! ticket--; }else{ System.out.println("你买不到票了"); } } }
解决:
(1)如果一个变量需要多个用户共享,则应当在访问该变量的时候,加同步机制
synchronized (对象){ //同步代码 }
public class MyServlet1 extends HttpServlet { int ticket = 2; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { synchronized (this) { if(ticket > 0){ System.out.println("你买到票了"); try { //线程休眠用来模拟成千上万个人同时并发,因为一个售票系统会有很多人同时访问! Thread.sleep(10 * 1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //先休眠再减!!买完票还没来得及减另一个人就来买了! ticket--; }else{ System.out.println("你买不到票了"); } } } }
(2)如果一个变量不需要共享,则直接在doGet()或者doPost()定义,这样不会存在线程安全问题.
public class MyServlet1 extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int j = 0; j ++; response.getWriter().println("j=" + j); } }
无论谁请求j的值都是1.
5.servlet 中的 <load-on-startup> 配置
如果在<servlet>元素中配置了一个<load-on-startup>元素,那么web应用程序在启动时,就会装载并创建servlet实例对象,以及调用serlvet实例对象的init()方法。
需求: 当我们的网站启动的时候,可能会要求初始化一些数据,(比如创建临时表), 在比如:
我们的网站有一些要求定时完成的任务[ 定时写日志,定时备份数据.. 定时发送邮件..]
解决方法: 可以通过 <load-on-startup> 配合线程知识搞定.
先说明<load-on-startup>: 通过配置<load-on-startup> 我们可以指定某个Servlet 自动创建.
<load-on-startup>1</load-on-startup>
这个1是指servlet被初始化的顺序。
对于一个大型的网站来说,初始化的servlet可能不止一个,它们的相对执行顺序用数字表示
任务:web应用启动时创建一个后台线程,定时完成某些任务(每隔十秒发一封邮件)。
我们来模拟一个定时发送电子邮件的功能:这个功能应该在网站启动的时候就开始
实现思路:
sendEmailTable
id content sendtime
1 "hello" 2011-11-11 20:11
2 "hello2" 2012-11-11 10:00
public class SendEmailThread extends Thread{ @Override public void run() { int i=0; try { //这个事应该在一直执行。 while(true){ //每休眠一分钟,就去扫表sendmail, 看看那份信件应当被发出 Thread.sleep(10*1000); System.out.println("发出 第"+(++i)+"邮件");//javamail } } catch (Exception e) { e.printStackTrace(); // TODO: handle exception } } }
public class MyInitServlet extends HttpServlet { private static final long serialVersionUID = 1L; public void init() throws ServletException { // Put your code here System.out.println("MyInitServlet1 的init被调用.."); //完成一些初始化任务 System.out.println("创建数据库,表,读取参数"); //创建一个线程 SendEmailThread sendEmailThread=new SendEmailThread(); sendEmailThread.start(); } }
ServletConfig对象
该对象主要用于 读取 servlet的配置信息.
<servlet> <servlet-name>ServletConfigTest</servlet-name> <servlet-class>com.hsp.servlet.ServletConfigTest</servlet-class> <!-- 这里可以给servlet配置信息,这里配置的信息,只能被该servlet 读取 --> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </servlet>
如何使用
String encoding = this.getServletConfig().getInitParameter("encoding"); response.setCharacterEncoding(encoding);
servlet可以指定编码方式
补充说明:这种配置参数的方式,只能被某个Servlet独立使用.如希望让所有的Servlet都去读取某个参数,这样配置:
<!-- 如果这里配置参数,可被所有servlet读取 --> <!-- <context-param> <param-name></param-name> <param-value></param-value> </context-param> -->
如果要把所有的参数都读取,则使用 如下方法 : Enumeration<String> names=this.getServletConfig().getInitParameterNames(); while(names.hasMoreElements()){ String name=names.nextElement(); System.out.println(name); System.out.println(this.getServletConfig().getInitParameter(name)); }
Servlet的一些细节问题的更多相关文章
- servlet中的细节
Get方法有大小限制:1024个字符.这些信息使用 Query_String头传递,并通过Query_String环境变量访问.Post方法:请求体信息使用FromData头传递.读取所有表单参数:g ...
- Servlet的一些细节(2)
1. Servlet的创建时间 Servlet是不能单独运行,调用它的叫做Servlet引擎,或者叫做web服务器 针对客户端的多长Servlet请求,通常情况下,服务器只会创建一个Servlet实例 ...
- Servlet的一些细节(1)
1. Servlet程序必须映射到一个URL地址 由于客户端是通过URL访问web服务器资源,所以Servlet程序必须映射到一个URL地址.这个工作在web.xml文件中使用<servlet ...
- [Java.Web] Servlet 的一些细节
本文来自 传智播客视频PPT 1. 由于客户端是通过 URL 地址访问 web 服务器中的资源,所以 Servlet 程序若想被外界访问,必须把 servlet 程序映射到一个 URL 地址上,这个工 ...
- Servlet的一些细节
由于客户端是通过URL地址访问web服务器的中的资源的,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用<servlet& ...
- 2016-2-1 Servlet细节
Servlet的一些细节(韩顺平老师视频讲解)(1)由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序想要被外界访问,必须把servlet程序映射到一个URL地址上.这个工作在 ...
- JavaWeb -- Servlet运行过程 和 细节
Servlet的运行过程 lServlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后: ①Web服务器首先检查是否已经装载并创建了该Servlet的实例对象.如果是,则 ...
- Servlet映射细节
Servlet的映射细节: 1):一个Servlet程序(Web组件),可以配置多个<url-pattern>,表示一个Servlet有多个资源名称. <servlet-mappin ...
- java web学习总结(五) -------------------servlet开发(一)
一.Servlet简介 Servlet是sun公司提供的一门用于开发动态web资源的技术. Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向 ...
随机推荐
- 通过命令行连接oracle数据库/进入sql plus
1.直接打开SQL Plus登录,需要用户名和密码 开始->程序->Oracle->应用程序开发->sqlplus 我的电脑是“开始”->“Oracle - OraDb1 ...
- IE浏览器打开 「兼容性视图」
有些IE上的网页控件需要打开兼容性视图才能使用,不知道是Javascript的原因,还是CSS的原因. 使用环境是用C语言配合boa服务器实现的CGI程序.
- WIN32一些文件及窗口操作
0,获取指定的系统路径: #include <shlobj.h> #pragma comment(lib, "shell32.lib") TCHAR szPat ...
- TCP/IP:链路层
链路层主要目的: 1. 为IP模块发送和接收IP数据报. 2. 为ARP模块发送ARP请求和接收ARP应答. 3. 为RARP发送RARP请求和接收RARP应 ...
- 连接ACCESS的AccessHelper.cs类
using System; using System.Data; using System.Configuration; using System.Data.OleDb; using System.C ...
- PHPNow升级PHP版本的方法
在WIN上有时候需要测试一些PHP程序,又不会自行独立配置环境,那么PHPNow是非常好的选择. PHPNow自带的PHP版本为5.2.14,而最后一次更新在于2010-9-22,PHP5.2对于现在 ...
- 解决Win7系统安装时“安装程序无法定位现有 系统分区,也无法创建新的系统分区”提示
第一步:U盘启动装系统时,格式化主分区的内容后出现上面的问题 第二步:重启机器,通过U 盘启动.进入win pe系统. 第三步:把windows 7的ISO镜像解压到电脑的非系统盘的其他硬盘上.如D: ...
- .NET基础之集合
集合可以说是数组的超集,集合可以维护对象数组,集合包含了更高级的功能.例如控制对其包含的对象的访问.搜索和排序等.数组是固定的,一旦我们创建好了数组,不能在现有数组的末尾添加新项,除非我们创建新的数组 ...
- hadoop可能遇到的问题
1.hadoop运行的原理? 2.mapreduce的原理? 3.HDFS存储的机制? 4.举一个简单的例子说明mapreduce是怎么来运行的 ? 5.面试的人给你出一些问题,让你用mapreduc ...
- ubuntu find方法
通用格式:find pathname -options [-print -exec -ok]例子:find / -name filename 再根目录里面搜索文件名为filename的文件find / ...