使用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")来得到"[email protected]"。

  1.   InitTest
  2.   coreservlets.InitServlet
  3.   
  4.     firstName
  5.     Larry
  6.   
  7.   
  8.     emailAddress
  9.     [email protected]
  10.   


  11.   InitTest
  12.   /showInitValues
复制代码
在处理初始化参数时,重点关注以下内容。

返回值  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("
  24.                   "Transitional//EN\">" + "\n" +
  25.                   "\n" + "" +<br></li> <li style="margin-left:30px;border-top-width:0px;border-right-width:0px;border-bottom-width:0px;border-left-width:0px;list-style-type:decimal;">                   "Init Servlet" + "\n" +
  26.                   "\n" +
  27.                   "

    Init Parameters:

    \n" +
  28.                   "
      \n" +
    •                   "
    • First name: " + firstName + "\n" +
    •                   "
    • Email address: " + emailAddress + "\n" +
    •                   "
    \n" +
  29.                   "");
  30.   }
  31. }
复制代码
清单2.9  web.xml (节选,说明初始化参数)

  1.            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2.            xsi:schemaLocation=
  3.            "http://java.sun.com/xml/ns/j2ee
  4.            http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  5.            version="2.4">
  6.   
  7.     InitTest
  8.     coreservlets.InitServlet
  9.     
  10.       firstName
  11.       Larry
  12.     
  13.     
  14.       emailAddress
  15.       [email protected]
  16.     
  17.   
  18.   
  19.     InitTest
  20.     /showInitValues
  21.   
  22.   
复制代码
二、分配JSP初始化参数
虽然servlet规范提供了JSP初始化参数的分配机制,但实际上并不鼓励这么做,也很少这么做。加载初始化参数更好的方法是使用Model-View-Controller(MVC)架构并在 servlet的init方法中进行初始化。相较于为servlet提供初始化参数,为JSP页面提供初始化参数有以理三个不同的方法。

(1)   可以使用jsp-file代替servlet-class  WEB-INF/web.xml的servlet元素应如下所示:

  1.   InitPage
  2.   /InitPage.jsp
  3.   
  4.     ...
  5.     ...
  6.   
  7.   ...
复制代码
(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.   InitPage
  2.   /InitPage.jsp
复制代码
(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. JSP Init Test

  2. Init Parameters:



    •   
    • First name: <%= firstName %>
    •   
    • Email address: <%= emailAddress %>





  3. <%!
  4. private String firstName = "First name is missing.";
  5. private String emailAddress = "Email address is missing";
  6. public void jspInit() {
  7.   ServletConfig config = getServletConfig();
  8.   if (config.getInitParameter("firstName") != null) {
  9.     firstName = config.getInitParameter("firstName");
  10.   }
  11.   if (config.getInitParameter("emailAddress") != null) {
  12.     emailAddress = config.getInitParameter("emailAddress");
  13.   }
  14. }
  15. %>
复制代码
清单2.11  web.xml (节选,显示JSP页面的初始化参数)

  1.           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2.           xsi:schemaLocation=
  3.           "http://java.sun.com/xml/ns/j2ee
  4.           http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  5.           version="2.4">


  6.   InitPage
  7.   /InitPage.jsp
  8.   
  9.     firstName
  10.     Bill
  11.   
  12.     
  13.       emailAddress
  14.       [email protected]
  15.     
  16.   

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

可以使用context-param元素来声明这些系统范围内的初始化参数值。Context-param元素将包含param-name,param-value和可选的description子元素。如下所示:

  1.   support-email
  2.   [email protected]
复制代码
四、服务器启动时加载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("
  21.                   "Transitional//EN\">" + "\n" +
  22.                   "\n" + "" +<br></li> <li style="margin-left:30px;border-top-width:0px;border-right-width:0px;border-bottom-width:0px;border-left-width:0px;list-style-type:decimal;">                   "Load Init Servlet" + "\n" +
  23.                   "\n" +
  24.                   "

    Init Parameter:

    \n" +
  25.                   "Company name: " +
  26.                   getServletContext().getAttribute("companyName") +
  27.                   "\n" + "");
  28.   }
  29. }
复制代码
清单2.13  ShowInitLoaded1.jsp


  1. Current Company Name

  2. Welcome to ${companyName}!


  3. We changed our name to serve you better!
复制代码
清单2.14  ShowInitLoaded2.jsp


  1. Init Parameter from ServletContext

  2. Init Parameter: ${companyName}


复制代码
但如果我们重启服务器后在没有调用 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.       LoadInit
  2.       
  3.         coreservlets.LoadInitServlet
  4.       
  5.       
  6.         companyName
  7.         Doozilch Daley Inc.
  8.       
  9.       0
复制代码
服务器启动时,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.   Search
  2.   myPackage.SearchServlet
  3.   0



  4.   Results
  5.   /results/index.jsp
  6.   1
复制代码
我们为不同的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方法中。在载入其他任何资源之前,容器肯定会调用这个方法。

你可能感兴趣的:(J2ee)