servletconfig对象+servletcontext对象
2017-10-18 14:38
387 查看
HttpServletRequest:请求对象:获取请求信息
HttpServletResponse:响应对象:设置响应对象
ServletConfig对象:servlet配置对象
ServletContext对象:servlet的上下文对象
作用:主要用于加载servlet的初始化参数,在一个web应用中可以存在多个ServletConfig对象(一个Servlet对应一个ServletConfig对象)
对象的创建和得到:
创建时机:在创建完servlet对象之后,在调用init方法之前创建
得到对象:直接从有参数的init方法中得到。
servlet的初始化参数配置
1)tomcat服务器把<init-param>中的参数加载web应用的时候,封装到ServletConfig对象中
2)tomcat服务器调用init方法传入ServletConfig对象
注意:servlet的参数只能由当前的这个servlet获取
ServletConfig的api:
getInitParameter(String name);//根据参数名获取参数值
getInitParameterNames();//得到servlet初始化的所有参数
getServletContext();//得到servlet上下文对象
getServletName();//得到servlet的名称
ServletConfig对象,叫做Servlet的上下文对象。表示一个当前的web应用环境。一个web应用中只有一个ServletContext对象。
创建时间:加载web应用时创建ServletContext对象。
得到:从ServletConfig的getServletContext方法得到。
sun公司设计:
1)创建ServletContext对象 ServletContext context=new ServletContext();
2)创建ServletConfig对象 ServletConfig config=new ServletConfig();
config.setServletContext(context);
Class ServletConfig{
ServletContext context;
public ServletContext getServletContext(){
return context;
}
}
public void init(ServletConfig config){
得到ServletConfig对象
从ServletConfig对象中得到ServletContext对象
ServletContext context=config.getServletContext();
}
getContextPath();得到当前web应用的路径
getInit
24000
Parameter(String name);得到web应用的初始化参数
getInitParameterNames()
setAttribute(String name,Object object);和域对象有关的方法
getAttribute(String name);
removeAttribute(String name);
getRequestDispather(String path);转发(类似与重定向)
getRealPath(String path);得到web应用的资源文件
getResourceAsStream(String path);
ServletContext,是一个全局的储存信息的空间,服务器开始,其就存在,服务器关闭,其才释放。request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。
换一种方式说吧,运行在JAVA虚拟机中的每一个Web应用程序都有一个与之相关的Servlet上下文。ServletContext对象是Web服务器中的一个已知路径的根,Servlet上下文被定位于http://localhost:8080/项目名.以
/项目名 请求路径(称为上下文路径)开始的所有请求被发送到与此ServletContext关联的Web应用程序。一个ServletContext对象表示了一个Web应用程序的上下文。
Servlet上下文:Servlet上下文提供对应用程序中所有Servlet所共有的各种资源和功能的访问。Servlet上下文API用于设置应用程序中所有Servlet共有的信息。Servlet可能需要共享他们之间的共有信息。运行于同一服务器的Servlet有时会共享资源,如JSP页面、文件和其他Servlet。
举例:
如,做一个购物类的网站,要从数据库中提取物品信息,如果用session保存这些物品信息,每个用户都访问一便数据库,效率就太低了;所以要用来Servlet上下文来保存,在服务器开始时,就访问数据库,将物品信息存入Servlet上下文中,这样,每个用户只用从上下文中读入物品信息就行了。
3.1 ServletContext接口简介
ServletContext接口定义了运行servlet的web应用的servlet视图。容器供应商负责提供servlet容器内ServletContext接口的实现。使用ServletContext对象,servlet可以记录事件日志,获取资源的URL地址,并且设置和保存上下文内可以访问的其他servlet的属性。
ServletContext以web的已知路径为根路径。比如,假定一个servlet上下文位于http://www.mycorp.com/catalog。以/catalog请求路径开头的所有请求,已知为上下文路径,被路由到和该ServletContext关联的web应用。
3.2 ServletContext接口作用域
容器中部署的每一个web应用都有一个ServletContext接口的实例对象与之关联。如果容器被分布在多个虚拟机上,一个web应用将在每一个VM中有一个ServletContext实例。
不作为web应用一部分部署的容器中的servlet默认是“默认”web应用的一部分,有一个默认的ServletContext。在分布式容器中。默认ServletContext是非分布式的,并且必须只存在于一个VM中。
3.3 初始化参数
ServletContext接口的初始化参数允许servlet访问与web应用相关的上下文初始化参数,这些由应用开发人员在部署描述符中指定:
getInitParameter
getInitParameterNames
应用开发人员利用初始化参数传送配置信息。典型的例子是web管理员的e-mail地址或者一个持有关键数据的系统名称。
3.4 上下文属性
servlet可以通过名称将对象属性绑定到上下文。任何绑定到上下文的属性可以被同一个web应用的其他servlet使用。ServletContext接口的下列方法允许访问这种功能:
setAttribute
getAttribute
getAttributeNames
removeAttribute
3.4.1 分布式容器中的上下文属性
上下文属性对于创建它们的VM来说是本地的。这防止ServletContext属性存储于分布式容器的共享内存中。当信息需要在运行于分布式环境中的servlet之间共享时,信息被放入会话中(参见第7章“会话”),存储于数据库中,或者存储于EJB组件中。
3.5 资源
ServletContext接口通过下列方法提供对web应用组成的静态内容文档层级的直接访问,包括HTML,GIF和JPEG文件:
getResource
getResourceAsStream
getResource和getResourceAsStream方法以“/”开头的字符串为参数,它指定上下文根路径的资源相对路径。文档的层级可能存在于服务器的文件系统,war文件,远程服务器或者在一些其它位置中。
这些方法不用来获取动态内容。比如,在一个支持JSP规范1的容器中,getResource("/index.jsp")这种形式的方法调用将返回JSP源代码,而不是处理后的输出。关于访问动态内容的更多信息参见第8章“转发请求”。
Web应用资源的完整列表可以使用getResourcePaths(String path)方法访问。该方法语义的完整信息可以在本规范的API文档中找到。
3.6 多个主机和ServletContext
Web服务器可能支持一个服务器上多个逻辑主机共享一个IP地址。这功能有时被称为“虚拟主机”。这种情况下,每一个逻辑主机必须有它自己的servlet上下文或者servlet上下文组。Servlet上下文不可以被多个虚拟主机共享。
3.7 重载考虑
尽管容器供应商因为对于易于开发而实现的类加载不做要求,但是任何那样的实现必须确保所有它们可能使用2的所有servlet和类,被加载在单个类加载器作用域内。必须保证应用应该如开发人员预想的那样运转。作为开发辅助,绑定监听器的会话通知的完整语义应当由容器支持,在类加载上会话终止的监听上使用。
上一代的容器创建新的类加载器以加载servlet,这和用来加载servlet上下文中使用的其他servlet或者类的类加载器不同。这可能造成servlet上下文内的对象引用指向一个意想不到的类或对象,造成意想不到的行为。需要阻止由新一代类加载器所引发的问题。
3.7.1 临时工作目录
每一个servlet上下文都需要一个临时存储目录。Servlet容器必须为每一个servlet上下文提供一个私有的临时目录,并且使它可以通过javax.servlet.context.tempdir上下文属性可用。这些属性关联的对象必须是java.io.File类型。
这项需求认可了很多servlet引擎实现中提供的常见便利。容器不需要在servlet重启时维持临时目录的内容,但是需要确保一个servlet上下文的临时目录的内容对于该servlet容器上运行的其他web应用的servlet上下文不可见。
●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的对外访问路径。
★这里需要注意的是,一个servlet可以被多次映射,也即一个Servlet可以有多个<servlet-mapping>,对外提供多个访问路径。举例如下:
[html] view
plain copy
<servlet>
<servlet-name>MyServlet1</servlet-name>
<servlet-class>com.gavin.servlet.MyServlet1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet1</servlet-name>
<url-pattern>/MyServlet1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyServlet1</servlet-name>
<url-pattern>/Gavin.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyServlet1</servlet-name>
<url-pattern>/servlet/Gavin.html</url-pattern>
</servlet-mapping>
这里可以看到,我们将MyServlet1映射成了一个名字为MyServlet1,另一个名字为Gavin.html,还有一个名字为/servlet/Gavin.html。这里也得出结论:
★后缀名为html的资源不一定真的就是html。
★映射的名字可以有多级,有多个斜杠。
★在Servlet映射到的URL中也可以用*通配符,但只能有两种固定的格式,一种格式是“*.扩展名”,另一种是以正斜杠(/)开头并以”/*”结尾。
[html] view
plain copy
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>/news/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
则第一种可以匹配任何名字的servlet,第二种可以匹配前面有一层为news的servlet,这种方法可以应用在:比如一个网站要对新闻版块进行整改,则可以用这种方法将新闻版块的请求指向其他地方,将其暂时关闭。第三种匹配后缀为do的servlet。
匹配原则:在匹配的时候,(1)看谁的匹配度高,谁就被选中;(2)【*.后缀名】的优先级最低,实在没有匹配项的时候才匹配这个。
看一个面试题:
对于如下的一些映射关系:
Servlet1映射到/abc/*
Servlet2映射到/*
Servlet3映射到/abc
Servlet映射到*.do
当请求URL为“/abc/a.html”,“/abc/*”和”/*”都匹配,哪个Servlet响应?
答案:Servlet1
当请求URL为“/abc”时,”/abc/*”、”/abc”和”/*”都匹配,哪个Servlet响应?
答案:Servlet3
当请求URL为“/abc/a.do”,“/abc/*”和”
*.do”都匹配,哪个Servlet响应?
答案:Servlet1
当请求URL为“/a.do”,“/*”和”*.do”都匹配,哪个Servlet响应?
答案:Servlet2à【*.后缀名】的优先级最低
5、当请求URL为“/xxx/yyy/a.do”,“/*”和”
*.do”都匹配,哪个Servlet响应?
答案:Servlet2à还是【*.后缀名】的优先级最低
通配符的价值在于可以在网站某版块或者整个网站进行维护时,进行暂时的关闭版块或网站。
(四)Servlet是一个供其他java程序(Servlet引擎)调用的java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度
(五)针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,(单例模式)也就是说Servlet实例一旦创建,它就会驻留在内存中,为后续的其他请求服务,直至web容器退出/或者reload该web运用,servlet实例对象才会销毁。
★Servlet单例模式存在线程安全问题,要注意并发处理,比如买票系统,票是所有客户端共享的,那么售票的代码应该使用同步机制。
synchronized(this){
}
如果一个变量不是共享的,就不需要设置为成员变量,只需要在doGet或者doPost方法中定义为局部变量即可。
(六)在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,service方法再根据请求方式分别调用doXXX方法。
(七)★如果在<servlet>元素中配置了一个<load-on-startup>元素,那么web应用程序启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法。
用途:为web应用写一个InitServlet,这个Servlet配置为启动时装载,为整个web应用创建必要的数据库表和数据。或者是启动一个后台线程,定时去完成某些工作(比如每隔10秒发一封电子邮件)
举例:
新建Servlet为InitServlet,其代码如下:
[java] view
plain copy
package com.gavin.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class InitServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
//初始化函数
public void init() throws ServletException {
System.out.println("InitServlet的init函数被调用...");
System.out.println("创建库、表...或者定时任务...");
}
}
其中只写了init函数的代码。在web.xml部署如下,其不用<servlet-mapping>映射,因为它只要在启动web应用时调用,而不需要外部访问。
[html] view
plain copy
<servlet>
<servlet-name>InitServlet</servlet-name>
<servlet-class>com.gavin.servlet.InitServlet</servlet-class>
<!-- 这里的1表示所有自启动的servlet的启动顺序,可以用1、2、3... -->
<load-on-startup>1</load-on-startup>
</servlet>
这里的1表示所有自启动的servlet的启动顺序,可以用1、2、3...
启动Tomcat服务器,可以看到:
启动Tomcat服务器的同时,这个Servlet已经被装载到内存了。
这里我们来模拟一个定时发送电子邮件的功能,实现思路:
这里当用户设定了一个定时发送邮件的任务后,数据库里肯定存在一张表,大概如下:
这里只是做一个简单的模拟,新建一个sendMainThread线程类
[java] view
plain copy
package com.gavin.model;
public class SendMailThread extends Thread {
public void run() {
int i = 0;
while (true) {
try {
// 每休眠一分钟,就去扫表sendmail,看看哪些信件应当发送
Thread.sleep(1000 * 10);
System.out.println("发出 第" + (++i) + "封信件");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
在InitServlet中创建该线程,并启动即可
[java] view
plain copy
public void init() throws ServletException {
System.out.println("InitServlet的init函数被调用...");
System.out.println("创建库、表...或者定时任务...");
//创建一个线程
SendMailThread sendMailThread = new SendMailThread();
sendMailThread.start();
}
效果:
当然真实的情况应该是要比对数据库中的时间的。
大型的网站会有多个自启动的Servlet,这里要用1、2、3….表示启动的顺序。前面也提到了!
●ServletConfig对象
◆在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数。
◆当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以得到当前servlet的初始化参数信息。
如下:
[html] view
plain copy
<servlet>
<servlet-name>MyServlet1</servlet-name>
<servlet-class>com.gavin.servlet.MyServlet1</servlet-class>
<!-- 这里可以给servlet配置信息,这里的配置信息,只能被该servlet读取 -->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</servlet>
说明:这里的配置参数方法,只能被该servlet读取,而不能被其他servlet使用
在Servlet程序中,可以读取出设置参数,如下:
[java] view
plain copy
response.setCharacterEncoding(this.getInitParameter("encoding"));
如果有多个参数,可以使用getInitParameterNames()方法,该方法返回枚举类型Enumeration,可以通过for循环拿到对应的参数名称,然后通过参数名称再通过上述方法拿到参数,当然也可以一个个拿到。
◆当然,还有一种全局的参数设置,<context-param>节点也可以配置初始化参数,并且可以被所有servlet读取。
HttpServletResponse:响应对象:设置响应对象
ServletConfig对象:servlet配置对象
ServletContext对象:servlet的上下文对象
ServletConfig对象
作用:主要用于加载servlet的初始化参数,在一个web应用中可以存在多个ServletConfig对象(一个Servlet对应一个ServletConfig对象)对象的创建和得到:
创建时机:在创建完servlet对象之后,在调用init方法之前创建
得到对象:直接从有参数的init方法中得到。
servlet的初始化参数配置
1 <servlet> 2 <servlet-name>Demo1</servlet-name> 3 <servlet-class>com.maodoer.test.Demo1</servlet-class> 4 <load-on-startup>1</load-on-startup> 5 <!-- 初始化参数,这些参数会在加载web应用的时候封装到ServletConfig对象中 --> 6 <init-param> 7 <param-name>path</param-name> 8 <param-value>c:/users/maodoer/desktop/a.txt</param-value> 9 </init-param> 10 </servlet>
1)tomcat服务器把<init-param>中的参数加载web应用的时候,封装到ServletConfig对象中
2)tomcat服务器调用init方法传入ServletConfig对象
servlet的初始化参数设置
注意:servlet的参数只能由当前的这个servlet获取ServletConfig的api:
getInitParameter(String name);//根据参数名获取参数值
getInitParameterNames();//得到servlet初始化的所有参数
getServletContext();//得到servlet上下文对象
getServletName();//得到servlet的名称
1 public class Demo1 extends HttpServlet{ 2 /** 3 * 以下注释代码GenericServlet已经帮开发者写好了,所以不需要再写了。 4 */ 5 /*ServletConfig config=null; 6 @Override 7 public void init(ServletConfig config) throws ServletException { 8 this.config=config; 9 }*/ 10 @Override 11 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 12 /** 13 * 读取servlet的初始参数 14 */ 15 String path = this.getServletConfig().getInitParameter("path"); 16 File file=new File(path); 17 //读取内容 18 BufferedReader br=new BufferedReader(new FileReader(file)); 19 String str=null; 20 while((str=br.readLine())!=null){ 21 System.out.println(str); 22 } 23 //查询当前servlet的所有初始化参数 24 Enumeration<String> enums = this.getServletConfig().getInitParameterNames(); 25 while(enums.hasMoreElements()){ 26 String paramName = enums.nextElement(); 27 String paramValue = this.getServletConfig().getInitParameter(paramName); 28 System.out.println(paramName+"="+paramValue); 29 } 30 //得到servlet的名称 31 String servletName = this.getServletConfig().getServletName(); 32 System.out.println(servletName); 33 } 34 }
ServletContext对象:
ServletConfig对象,叫做Servlet的上下文对象。表示一个当前的web应用环境。一个web应用中只有一个ServletContext对象。
对象创建和得到:
创建时间:加载web应用时创建ServletContext对象。得到:从ServletConfig的getServletContext方法得到。
sun公司设计:
1)创建ServletContext对象 ServletContext context=new ServletContext();
2)创建ServletConfig对象 ServletConfig config=new ServletConfig();
config.setServletContext(context);
Class ServletConfig{
ServletContext context;
public ServletContext getServletContext(){
return context;
}
}
public void init(ServletConfig config){
得到ServletConfig对象
从ServletConfig对象中得到ServletContext对象
ServletContext context=config.getServletContext();
}
ServletContext核心api:
getContextPath();得到当前web应用的路径getInit
24000
Parameter(String name);得到web应用的初始化参数
getInitParameterNames()
setAttribute(String name,Object object);和域对象有关的方法
getAttribute(String name);
removeAttribute(String name);
getRequestDispather(String path);转发(类似与重定向)
getRealPath(String path);得到web应用的资源文件
getResourceAsStream(String path);
ServletContext,是一个全局的储存信息的空间,服务器开始,其就存在,服务器关闭,其才释放。request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。
换一种方式说吧,运行在JAVA虚拟机中的每一个Web应用程序都有一个与之相关的Servlet上下文。ServletContext对象是Web服务器中的一个已知路径的根,Servlet上下文被定位于http://localhost:8080/项目名.以
/项目名 请求路径(称为上下文路径)开始的所有请求被发送到与此ServletContext关联的Web应用程序。一个ServletContext对象表示了一个Web应用程序的上下文。
Servlet上下文:Servlet上下文提供对应用程序中所有Servlet所共有的各种资源和功能的访问。Servlet上下文API用于设置应用程序中所有Servlet共有的信息。Servlet可能需要共享他们之间的共有信息。运行于同一服务器的Servlet有时会共享资源,如JSP页面、文件和其他Servlet。
举例:
如,做一个购物类的网站,要从数据库中提取物品信息,如果用session保存这些物品信息,每个用户都访问一便数据库,效率就太低了;所以要用来Servlet上下文来保存,在服务器开始时,就访问数据库,将物品信息存入Servlet上下文中,这样,每个用户只用从上下文中读入物品信息就行了。
3.1 ServletContext接口简介
ServletContext接口定义了运行servlet的web应用的servlet视图。容器供应商负责提供servlet容器内ServletContext接口的实现。使用ServletContext对象,servlet可以记录事件日志,获取资源的URL地址,并且设置和保存上下文内可以访问的其他servlet的属性。
ServletContext以web的已知路径为根路径。比如,假定一个servlet上下文位于http://www.mycorp.com/catalog。以/catalog请求路径开头的所有请求,已知为上下文路径,被路由到和该ServletContext关联的web应用。
3.2 ServletContext接口作用域
容器中部署的每一个web应用都有一个ServletContext接口的实例对象与之关联。如果容器被分布在多个虚拟机上,一个web应用将在每一个VM中有一个ServletContext实例。
不作为web应用一部分部署的容器中的servlet默认是“默认”web应用的一部分,有一个默认的ServletContext。在分布式容器中。默认ServletContext是非分布式的,并且必须只存在于一个VM中。
3.3 初始化参数
ServletContext接口的初始化参数允许servlet访问与web应用相关的上下文初始化参数,这些由应用开发人员在部署描述符中指定:
getInitParameter
getInitParameterNames
应用开发人员利用初始化参数传送配置信息。典型的例子是web管理员的e-mail地址或者一个持有关键数据的系统名称。
3.4 上下文属性
servlet可以通过名称将对象属性绑定到上下文。任何绑定到上下文的属性可以被同一个web应用的其他servlet使用。ServletContext接口的下列方法允许访问这种功能:
setAttribute
getAttribute
getAttributeNames
removeAttribute
3.4.1 分布式容器中的上下文属性
上下文属性对于创建它们的VM来说是本地的。这防止ServletContext属性存储于分布式容器的共享内存中。当信息需要在运行于分布式环境中的servlet之间共享时,信息被放入会话中(参见第7章“会话”),存储于数据库中,或者存储于EJB组件中。
3.5 资源
ServletContext接口通过下列方法提供对web应用组成的静态内容文档层级的直接访问,包括HTML,GIF和JPEG文件:
getResource
getResourceAsStream
getResource和getResourceAsStream方法以“/”开头的字符串为参数,它指定上下文根路径的资源相对路径。文档的层级可能存在于服务器的文件系统,war文件,远程服务器或者在一些其它位置中。
这些方法不用来获取动态内容。比如,在一个支持JSP规范1的容器中,getResource("/index.jsp")这种形式的方法调用将返回JSP源代码,而不是处理后的输出。关于访问动态内容的更多信息参见第8章“转发请求”。
Web应用资源的完整列表可以使用getResourcePaths(String path)方法访问。该方法语义的完整信息可以在本规范的API文档中找到。
3.6 多个主机和ServletContext
Web服务器可能支持一个服务器上多个逻辑主机共享一个IP地址。这功能有时被称为“虚拟主机”。这种情况下,每一个逻辑主机必须有它自己的servlet上下文或者servlet上下文组。Servlet上下文不可以被多个虚拟主机共享。
3.7 重载考虑
尽管容器供应商因为对于易于开发而实现的类加载不做要求,但是任何那样的实现必须确保所有它们可能使用2的所有servlet和类,被加载在单个类加载器作用域内。必须保证应用应该如开发人员预想的那样运转。作为开发辅助,绑定监听器的会话通知的完整语义应当由容器支持,在类加载上会话终止的监听上使用。
上一代的容器创建新的类加载器以加载servlet,这和用来加载servlet上下文中使用的其他servlet或者类的类加载器不同。这可能造成servlet上下文内的对象引用指向一个意想不到的类或对象,造成意想不到的行为。需要阻止由新一代类加载器所引发的问题。
3.7.1 临时工作目录
每一个servlet上下文都需要一个临时存储目录。Servlet容器必须为每一个servlet上下文提供一个私有的临时目录,并且使它可以通过javax.servlet.context.tempdir上下文属性可用。这些属性关联的对象必须是java.io.File类型。
这项需求认可了很多servlet引擎实现中提供的常见便利。容器不需要在servlet重启时维持临时目录的内容,但是需要确保一个servlet上下文的临时目录的内容对于该servlet容器上运行的其他web应用的servlet上下文不可见。
●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的对外访问路径。
★这里需要注意的是,一个servlet可以被多次映射,也即一个Servlet可以有多个<servlet-mapping>,对外提供多个访问路径。举例如下:
[html] view
plain copy
<servlet>
<servlet-name>MyServlet1</servlet-name>
<servlet-class>com.gavin.servlet.MyServlet1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet1</servlet-name>
<url-pattern>/MyServlet1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyServlet1</servlet-name>
<url-pattern>/Gavin.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyServlet1</servlet-name>
<url-pattern>/servlet/Gavin.html</url-pattern>
</servlet-mapping>
这里可以看到,我们将MyServlet1映射成了一个名字为MyServlet1,另一个名字为Gavin.html,还有一个名字为/servlet/Gavin.html。这里也得出结论:
★后缀名为html的资源不一定真的就是html。
★映射的名字可以有多级,有多个斜杠。
★在Servlet映射到的URL中也可以用*通配符,但只能有两种固定的格式,一种格式是“*.扩展名”,另一种是以正斜杠(/)开头并以”/*”结尾。
[html] view
plain copy
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>/news/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
则第一种可以匹配任何名字的servlet,第二种可以匹配前面有一层为news的servlet,这种方法可以应用在:比如一个网站要对新闻版块进行整改,则可以用这种方法将新闻版块的请求指向其他地方,将其暂时关闭。第三种匹配后缀为do的servlet。
匹配原则:在匹配的时候,(1)看谁的匹配度高,谁就被选中;(2)【*.后缀名】的优先级最低,实在没有匹配项的时候才匹配这个。
看一个面试题:
对于如下的一些映射关系:
Servlet1映射到/abc/*
Servlet2映射到/*
Servlet3映射到/abc
Servlet映射到*.do
当请求URL为“/abc/a.html”,“/abc/*”和”/*”都匹配,哪个Servlet响应?
答案:Servlet1
当请求URL为“/abc”时,”/abc/*”、”/abc”和”/*”都匹配,哪个Servlet响应?
答案:Servlet3
当请求URL为“/abc/a.do”,“/abc/*”和”
*.do”都匹配,哪个Servlet响应?
答案:Servlet1
当请求URL为“/a.do”,“/*”和”*.do”都匹配,哪个Servlet响应?
答案:Servlet2à【*.后缀名】的优先级最低
5、当请求URL为“/xxx/yyy/a.do”,“/*”和”
*.do”都匹配,哪个Servlet响应?
答案:Servlet2à还是【*.后缀名】的优先级最低
通配符的价值在于可以在网站某版块或者整个网站进行维护时,进行暂时的关闭版块或网站。
(四)Servlet是一个供其他java程序(Servlet引擎)调用的java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度
(五)针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,(单例模式)也就是说Servlet实例一旦创建,它就会驻留在内存中,为后续的其他请求服务,直至web容器退出/或者reload该web运用,servlet实例对象才会销毁。
★Servlet单例模式存在线程安全问题,要注意并发处理,比如买票系统,票是所有客户端共享的,那么售票的代码应该使用同步机制。
synchronized(this){
}
如果一个变量不是共享的,就不需要设置为成员变量,只需要在doGet或者doPost方法中定义为局部变量即可。
(六)在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,service方法再根据请求方式分别调用doXXX方法。
(七)★如果在<servlet>元素中配置了一个<load-on-startup>元素,那么web应用程序启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法。
用途:为web应用写一个InitServlet,这个Servlet配置为启动时装载,为整个web应用创建必要的数据库表和数据。或者是启动一个后台线程,定时去完成某些工作(比如每隔10秒发一封电子邮件)
举例:
新建Servlet为InitServlet,其代码如下:
[java] view
plain copy
package com.gavin.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class InitServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
//初始化函数
public void init() throws ServletException {
System.out.println("InitServlet的init函数被调用...");
System.out.println("创建库、表...或者定时任务...");
}
}
其中只写了init函数的代码。在web.xml部署如下,其不用<servlet-mapping>映射,因为它只要在启动web应用时调用,而不需要外部访问。
[html] view
plain copy
<servlet>
<servlet-name>InitServlet</servlet-name>
<servlet-class>com.gavin.servlet.InitServlet</servlet-class>
<!-- 这里的1表示所有自启动的servlet的启动顺序,可以用1、2、3... -->
<load-on-startup>1</load-on-startup>
</servlet>
这里的1表示所有自启动的servlet的启动顺序,可以用1、2、3...
启动Tomcat服务器,可以看到:
启动Tomcat服务器的同时,这个Servlet已经被装载到内存了。
这里我们来模拟一个定时发送电子邮件的功能,实现思路:
这里当用户设定了一个定时发送邮件的任务后,数据库里肯定存在一张表,大概如下:
Id | Content | sendTime |
1 | Hello | 2014-5-18 00:00 |
2 | Happy Birthday | 2014-5-20 13:14 |
[java] view
plain copy
package com.gavin.model;
public class SendMailThread extends Thread {
public void run() {
int i = 0;
while (true) {
try {
// 每休眠一分钟,就去扫表sendmail,看看哪些信件应当发送
Thread.sleep(1000 * 10);
System.out.println("发出 第" + (++i) + "封信件");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
在InitServlet中创建该线程,并启动即可
[java] view
plain copy
public void init() throws ServletException {
System.out.println("InitServlet的init函数被调用...");
System.out.println("创建库、表...或者定时任务...");
//创建一个线程
SendMailThread sendMailThread = new SendMailThread();
sendMailThread.start();
}
效果:
当然真实的情况应该是要比对数据库中的时间的。
大型的网站会有多个自启动的Servlet,这里要用1、2、3….表示启动的顺序。前面也提到了!
●ServletConfig对象
◆在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数。
◆当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以得到当前servlet的初始化参数信息。
如下:
[html] view
plain copy
<servlet>
<servlet-name>MyServlet1</servlet-name>
<servlet-class>com.gavin.servlet.MyServlet1</servlet-class>
<!-- 这里可以给servlet配置信息,这里的配置信息,只能被该servlet读取 -->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</servlet>
说明:这里的配置参数方法,只能被该servlet读取,而不能被其他servlet使用
在Servlet程序中,可以读取出设置参数,如下:
[java] view
plain copy
response.setCharacterEncoding(this.getInitParameter("encoding"));
如果有多个参数,可以使用getInitParameterNames()方法,该方法返回枚举类型Enumeration,可以通过for循环拿到对应的参数名称,然后通过参数名称再通过上述方法拿到参数,当然也可以一个个拿到。
◆当然,还有一种全局的参数设置,<context-param>节点也可以配置初始化参数,并且可以被所有servlet读取。
相关文章推荐
- javaweb-day05-5&6&7(Servlet - ServletConfig对象 和 ServletContext对象)
- ServletConfig与ServletContext对象详解
- mvc-servlet---ServletConfig与ServletContext对象详解(转载)
- JavaWeb学习笔记----Servlet的ServletConfig对象和ServletContext对象的使用
- ServletContext和ServletConfig对象
- ServletConfig与ServletContext对象详解
- ServletConfig与ServletContext对象详解
- ServletConfig对象与ServletContext区别
- servlet映射,线程安全,servletconfig对象,servletcontext对象
- ServletConfig与ServletContext对象详解
- ServletConfig与ServletContext对象详解
- (五)Servlet就是这样-ServletConfig和ServletContext对象
- 黑马第七天之Servlet知识,servletconfig,servletcontext,response三个对象的用法
- JavaWeb学习笔记(7)——ServletConfig和ServletContext对象
- ServletConfig与ServletContext对象详解
- (转)ServletConfig与ServletContext对象详解
- ServletConfig对象与ServletContext
- servlet都有一个servletConfig对象;四个config对象可以调用的方法;ServletContext对象之获取web项目信息;设置全局初始化参数的配置
- 第10天(就业班) servlet的映射路径、生命周期、自动加载+init方法+线程并发安全、servletconfig对象+servletcontext对象入门、servletcontext对象的使
- Servlet概述以及ServletConfig 和ServletContext对象的作用