使用web.xml配置Web应用之初始化和预加载servlet和JSP页面

本节讨论如何控制servlet和JSP页面的启动行为。具体说来,本节将解释如何分配初始化参数,如何在servlet和JSP页面加载时服务器的生命周期间进行修改。

一、分配servlet初始化参数
可以通过init-param元素(包含param-name和param-value这两个子元素)来为servlet提供初始化参数。例如,在下面的示例中,如果通过http://host/webAppPrefix/showinitValue 形式的URL来访问InitServlet ,它将从其init方法调用getServletConfig().getInitParameter("firstName")来得到"Larray";调用getServletConfig().getInitParameter("emailAddress")来得到"ellison@microsoft.com"。
  1. <servlet>
  2.   <servlet-name>InitTest</servlet-name>
  3.   <servlet-class>coreservlets.InitServlet</servlet-class>
  4.   <init-param>
  5.     <param-name>firstName</param-name>
  6.     <param-value>Larry</param-value>
  7.   </init-param>
  8.   <init-param>
  9.     <param-name>emailAddress</param-name>
  10.     <param-value>ellison@microsoft.com</param-value>
  11.   </init-param>
  12. </servlet>
  13. <servlet-mapping>
  14.   <servlet-name>InitTest</servlet-name>
  15.   <url-pattern>/showInitValues</url-pattern>
  16. </servlet-mapping>
复制代码
在处理初始化参数时,重点关注以下内容。

返回值    getInitParameter的返回值总是一个String值。所以对于整数类型的参数,可以使用Integer.parseInt来获得一个int值。

返回空值    如果传给getInitParameter方法的参数在servlet的init-param声明中没有出现,函数将返回null值。因为除了Java开发人员,没有人可以修改web.xml,所以应该养成习惯总是在代码中检查null值。

在JSP中初始化    JSP页面使用jspInit而不是init方法。JSP页面还要用jsp-file元素来代替servlet-class。

默认URL    初始化参数仅用于使用与其名称相关联的自定义URL路径访问时。所以在这个例子中,firstName和emailAddress初始化参数在仅用于http://host/webAppPrefix/showInitValues这个URL进行访问时。但在使用http://host/webAppPrefix/servlet/coreservlets.InitServlet访问时无效。

核心警告:servlet中的初始化参数在使用其默认URL访问时无效。

比如,清单2.8显示了一个简单的servlet,即InitServlet,它使用init方法来设置firstName和emailAddress。清单2.9显示了web.xml文件的部分内容,其中演示了为servlet配置/showInitValues URL。

记住哪个URL可以访问哪个不能访问实在太难。在实际的Web应用中,通常会禁用servlet默认访问路径,因而每个servlet只有一个URL。只有快测试时才会保留servlet特有的默认请求路径。

清单2.8    InitServlet.java
  1. package coreservlets;
  2. import java.io.*;
  3. import javax.servlet.*;
  4. import javax.servlet.http.*;

  5. public class InitServlet extends HttpServlet {
  6.   private String firstName = "First name is missing.";
  7.   private String emailAddress = "Email address is missing";
  8.   public void init() {
  9.     ServletConfig config = getServletConfig();
  10.     if (config.getInitParameter("firstName") != null) {
  11.       firstName = config.getInitParameter("firstName");
  12.     }
  13.     if (config.getInitParameter("emailAddress") != null) {
  14.         emailAddress = config.getInitParameter("emailAddress");
  15.     }
  16.   }

  17.   public void doGet(HttpServletRequest request,
  18.                        HttpServletResponse response)
  19.       throws ServletException, IOException {
  20.     response.setContentType("text/html");
  21.     PrintWriter out = response.getWriter();
  22.     String uri = request.getRequestURI();
  23.     out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " +
  24.                   "Transitional//EN\">" + "\n" +
  25.                   "<HTML>\n" + "<HEAD><TITLE>" +
  26.                   "Init Servlet" + "</TITLE></HEAD>\n" +
  27.                   "<BODY BGCOLOR=\"#FDF5E6\">\n" +
  28.                   "<H2>Init Parameters:</H2>\n" +
  29.                   "<UL>\n" +
  30.                   "<LI>First name: " + firstName + "\n" +
  31.                   "<LI>Email address: " + emailAddress + "\n" +
  32.                   "</UL>\n" +
  33.                   "</BODY></HTML>");
  34.   }
  35. }
复制代码
清单2.9    web.xml (节选,说明初始化参数)
  1. <?xml version="1.0" encoding="ISO-8859-1"?>
  2. <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  3.            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.            xsi:schemaLocation=
  5.            "http://java.sun.com/xml/ns/j2ee
  6.            http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  7.            version="2.4">
  8.   <servlet>
  9.     <servlet-name>InitTest</servlet-name>
  10.     <servlet-class>coreservlets.InitServlet</servlet-class>
  11.     <init-param>
  12.       <param-name>firstName</param-name>
  13.       <param-value>Larry</param-value>
  14.     </init-param>
  15.     <init-param>
  16.       <param-name>emailAddress</param-name>
  17.       <param-value>ellison@microsoft.com</param-value>
  18.     </init-param>
  19.   </servlet>
  20.   <servlet-mapping>
  21.     <servlet-name>InitTest</servlet-name>
  22.     <url-pattern>/showInitValues</url-pattern>
  23.   </servlet-mapping>
  24.   <!-- ... -->
  25. </web-app>
复制代码
二、分配JSP初始化参数
虽然servlet规范提供了JSP初始化参数的分配机制,但实际上并不鼓励这么做,也很少这么做。加载初始化参数更好的方法是使用Model-View-Controller(MVC)架构并在 servlet的init方法中进行初始化。相较于为servlet提供初始化参数,为JSP页面提供初始化参数有以理三个不同的方法。

(1)     可以使用jsp-file代替servlet-class    WEB-INF/web.xml的servlet元素应如下所示:
  1. <servlet>
  2.   <servlet-name>InitPage</servlet-name>
  3.   <jsp-file>/InitPage.jsp</jsp-file>
  4.   <init-param>
  5.     <param-name>...</param-name>
  6.     <param-value>...</param-value>
  7.   </init-param>
  8.   ...
  9. </servlet>
复制代码
(2)     将JSP页面的原始URL分配为其自定义URL路径    对于servlet,使用一个不同于servlet名称的自定义URL路径是非常常见的。从技术角度看,对JSP页面采用这种做法也是合法的。但是,许多用户在使用JSP页面时并不喜欢要引用常规servelt的URL。而且,如果JSP页面在服务器提供的目录列表中(比如,一个既没有 index.html,也没有index.jsp文件的目录),那么用户可能会获得一个链接打开JSP页面,无意中地调用未初始化的页面。所以,一个好的策略是使用url-pattern将JSP的原始URL与注册的servlet名称相关联。通过这个方法,客户端可以使用JSP的正常名称,但仍然调用自定义的版本。比如,假设已有定义了第一项的servlet定义,可能会使用下面的servlet-mapping定义:
  1. <servlet-mapping>
  2.   <servlet-name>InitPage</servlet-name>
  3.   <url-pattern>/InitPage.jsp</url-pattern>
  4. </servlet-mapping>
复制代码
(3)     JSP页面使用的是jspInit而不是init    由JSP页面生成的servlet可能已在使用init方法。因而,使用一个JSP声明来提供一个init方法是不合法的。必须创建一个名为jspInit的方法。

为了说明初始化JSP页面的过程,清单2.10显示了一个名为InitPage.jsp的JSP页面,该页面包含jspInit方法并且放在deployDemo Web应用程序的根目录下。通常,一个http://localhost/deployDemo/InitPage.jsp URL形式的URL会调用一个不能访问初始化参数因而返回null的页面。但是web.xml文件(清单2.11)分配了一个注册名并将注册名与 /InitPage.jsp的URL路径相关联。

清单2.10    InitPage.jsp
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD><TITLE>JSP Init Test</TITLE></HEAD>
  4. <BODY BGCOLOR="#FDF5E6">
  5. <H2>Init Parameters:</H2>
  6. <UL>
  7.   <LI>First name: <%= firstName %>
  8.   <LI>Email address: <%= emailAddress %>
  9. </UL>
  10. </BODY>
  11. </HTML>


  12. <%!
  13. private String firstName = "First name is missing.";
  14. private String emailAddress = "Email address is missing";
  15. public void jspInit() {
  16.   ServletConfig config = getServletConfig();
  17.   if (config.getInitParameter("firstName") != null) {
  18.     firstName = config.getInitParameter("firstName");
  19.   }
  20.   if (config.getInitParameter("emailAddress") != null) {
  21.     emailAddress = config.getInitParameter("emailAddress");
  22.   }
  23. }
  24. %>
复制代码
清单2.11    web.xml (节选,显示JSP页面的初始化参数)
  1. <?xml version="1.0" encoding="ISO-8859-1"?>
  2. <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  3.           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.           xsi:schemaLocation=
  5.           "http://java.sun.com/xml/ns/j2ee
  6.           http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  7.           version="2.4">
  8. <servlet>

  9.   <servlet-name>InitPage</servlet-name>
  10.   <jsp-file>/InitPage.jsp</jsp-file>
  11.   <init-param>
  12.     <param-name>firstName</param-name>
  13.     <param-value>Bill</param-value>
  14.   </init-param>
  15.     <init-param>
  16.       <param-name>emailAddress</param-name>
  17.       <param-value>gates@oracle.com</param-value>
  18.     </init-param>
  19.   </servlet>

  20.   <servlet-mapping>
  21.     <servlet-name>InitPage</servlet-name>
  22.     <url-pattern>/InitPage.jsp</url-pattern>
  23.   </servlet-mapping>
  24.   <!-- ... -->
  25. </web-app>
复制代码
三、提供应用程序范围的初始化参数
通常,我们会把初始化参数分配给单独的servlet或JSP页面。这个指定的servlet或者JSP页面通过ServletConfig的 getInitParameter方法来读取这些参数。但在某些情况下,需要提供系统范围内的初始化参数,任何servlet或者JSP页面可以通过 ServletContext的getInitParameter方法来读取这些初始化参数。

可以使用context-param元素来声明这些系统范围内的初始化参数值。Context-param元素将包含param-name,param-value和可选的description子元素。如下所示:
  1. <context-param>
  2.   <param-name>support-email</param-name>
  3.   <param-value>blackhole@mycompany.com</param-value>
  4. </context-param>
复制代码
四、服务器启动时加载servlet
假设 LoadInitServlet有一个init方法可以读取初始化参数companyName,并将其存储在ServletContext对象中。 LoadInitServlet的doGet方法从ServletContext中返回companyName值并在客户端显示。在 LoadInitServlet至少调用一次后,两个不同JSP页面ShowInitLoaded1.jsp和ShowInitLoaded2.jsp的任意位置都可以通过${companyName}输出参数值。JSP页面将返回之前存储在ServletContext中的companyName值并在客户端显示。在这种情况下,每个操作如期执行。LoadInitServlet.java,ShowInitLoaded1.jsp和 ShowInitLoaded2.jsp文件的完整代码如清单2.12~图2.14所示。

清单2.12    LoadInitServlet.java
  1. package coreservlets;
  2. import java.io.*;
  3. import javax.servlet.*;
  4. import javax.servlet.http.*;

  5. public class LoadInitServlet extends HttpServlet {
  6.   private String companyName = "Company name is missing";
  7.   public void init() {
  8.     ServletConfig config = getServletConfig();
  9.     if (config.getInitParameter("companyName") != null) {
  10.          companyName = config.getInitParameter("companyName");
  11.     }

  12.     ServletContext context = getServletContext();
  13.     context.setAttribute("companyName", companyName);
  14.   }

  15.   public void doGet(HttpServletRequest request,
  16.                        HttpServletResponse response)
  17.       throws ServletException, IOException {
  18.     response.setContentType("text/html");
  19.     PrintWriter out = response.getWriter();
  20.     out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " +
  21.                   "Transitional//EN\">" + "\n" +
  22.                   "<HTML>\n" + "<HEAD><TITLE>" +
  23.                   "Load Init Servlet" + "</TITLE></HEAD>\n" +
  24.                   "<BODY BGCOLOR=\"#FDF5E6\">\n" +
  25.                   "<H2>Init Parameter:</H2>\n" +
  26.                   "Company name: " +
  27.                   getServletContext().getAttribute("companyName") +
  28.                   "\n" + "</BODY></HTML>");
  29.   }
  30. }
复制代码
清单2.13    ShowInitLoaded1.jsp
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD><TITLE>Current Company Name</TITLE></HEAD>
  4. <BODY BGCOLOR="#FDF5E6">
  5. <H2>Welcome to ${companyName}!</H2>
  6. We changed our name to serve you better!
  7. </BODY></HTML>
复制代码
清单2.14    ShowInitLoaded2.jsp
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD><TITLE>Init Parameter from ServletContext</TITLE></HEAD>
  4. <BODY BGCOLOR="#FDF5E6">
  5. <H2>Init Parameter: ${companyName}</H2>
  6. </BODY></HTML>
复制代码
但如果我们重启服务器后在没有调用 LoadInitServlet之前重新刷新JSP页面,会发生什么情况?在这个时候,因为LoadInitServlet还没有被加载到内存,其 init方法还没有被调用,而且companyName属性还没有出现在ServletContext中,所以JSP页面无法显示出我们预期的结果。
在没有调用LoadInitServlet之前,重启服务器后但在调用ShowInitLoad1.jsp之前调用
http://localhost/deployDemo/ShowInitLoaded1.jsp的运行结果。公司名称绝对不会被载入
ServletContext,所以页面显示公司名为空

这个问题很容易解决,在contex-param中声明CompanyName即可,但随后在JSP页面中会出现Java代码,而且我们不得不在所有位置重复检查这个参数是否为null。所以,我们使用 load-on-startup以保证在Web应用程序首次加载的时候运行LoadInitServlet的init方法,如下所示:
  1. <servlet>
  2.       <servlet-name>LoadInit</servlet-name>
  3.       <servlet-class>
  4.         coreservlets.LoadInitServlet
  5.       </servlet-class>
  6.       <init-param>
  7.         <param-name>companyName</param-name>
  8.         <param-value>Doozilch Daley Inc.</param-value>
  9.       </init-param>
  10.       <load-on-startup>0</load-on-startup>
  11. </servlet>
复制代码
服务器启动时,LoadInitServlet便会被载入内存,它的init方法也随之被调用。如果我们在服务器重启后首先调用ShowInitLoad1.jsp,那么它现在会显示公司名称,因为LoadInitServlet的init方法绝对已经被调用了。

可以配置多个servlet或者JSP页面在服务器启动时加载。load-on-startup元素中的值为0,说明在服务器启动时这个servlet优先于其他任何servlet或JSP页面被加载到内存。这意味着服务器将优先加载编号较小的servlet或JSP页面。比如,下面的servlet(在Web应用程序WEB-INF目录下的 web.xml文件web-app元素中)将指示服务器首先加载和初始化SearchServlet,然后才加载和初始化Web应用程序results目录下index.jsp文件所产生的servlet。
  1. <servlet>
  2.   <servlet-name>Search</servlet-name>
  3.   <servlet-class>myPackage.SearchServlet</servlet-class>
  4.   <load-on-startup>0</load-on-startup>
  5. </servlet>
  6. <servlet>

  7.   <servlet-name>Results</servlet-name>
  8.   <jsp-file>/results/index.jsp</jsp-file>
  9.   <load-on-startup>1</load-on-startup>
  10. </servlet>
复制代码
我们为不同的servelt指定相同的load-on-startup编号,服务器将随机从编号相同的servlet中选择任意一个优先加载。如果在load-on-startup元素中设置负值,便无法保证这个servlet会在服务器启动时加载。

如果init方法(servlet)或者 jspInit方法(JSP)执行时间很长,load-on-startup特性也是十分有用的。比如,假设init方法或者jspInit方法从数据库或者ResourceBundle中查找数据。在这种情况下,在第一个客户端请求时才加载servlet这一默认行为会导致第一个客户端的严重延时。所以,可以使用servlet的load-on-startup子元素来规定在服务器首次启动时加载这个servlet。但是有一个更好的方法可解决这个问题,即把载入较慢的初始化代码放在ServletContextListener的contextInitialized方法中。在载入其他任何资源之前,容器肯定会调用这个方法。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值