有时当我们编写JEE Web应用时我们想要为应用部署人员提供一些灵活性例如或许你想要提供几个不同的应用版本每一个版本满足特定的用户的需要或许代码的有些部分需要主机名称和端口信息这些只有在部署时才知道或许你只想在如何显示数据方面给应用部署人员一些灵活性
你可以用环境变量增加这种灵活性环境变量是可以在组件的部署描述符文件中定义的参数应用组件通过JNDI按名称查找环境变量用环境变量的值定制应用的行为或表示
所有类型的应用组件都可以使用环境变量Servlet企业BeanJSP页面和用户tag都可以使用环境变量环境变量必须在组件的适当部署描述符文件中定义例如Web组件在webxml文件中定义企业Bean在ejbjarxml文件中定义
例如假定你要为电子商务应用编写一个servlet这个servlet发送email给客户通知客户收到了一个订单你的servlet需要授权的SMTP服务器的主机明端口登录名和口令作为组件(servlet)开发者你不必知道这些信息只要部署者知道就行了但是eamil功能要求这些信息如何向servle提供这些信息呢?
一个方法是使用servlet部署描述符文件(webxml)中的环境变量首先为主机名端口登录名口令定义环境变量然后编写代码通过JNDI从环境中得到这些环境变量的值在代码中使用这些环境变量的值部署者在部署时利用部署工具为这些环境变量填上适当的值程序运行时提取部署者设置的这些值使用这些值访问要访问的服务器
定义环境变量
用XML在组件的部署描述符文件中定义环境变量如果使用部署工具(例如JEE参考实现所带的部署工具程序)你就可以用GUI方式确定部署描述符但是下面我们还是假定用文本编辑器手工编辑部署描述符
环境变量有四个部分
;描述 定义在scription> tag 内的一个串
;名称定义在<enventryname> tag内的一个串
;值定义在<enventryvalue> tag内的一个值
;类名定义在<enventrytype> tag内的环境变量的类型
描述是可选的文字描述出现在部署工具的用户界面上它告诉部署者在确定环境实体引用时做什么换句话说它是一个可读描述告诉部署者如何填写其他值它也告诉部署者这个环境变量是否是可选的
环境变量的名称是相对于JNDI上下文名jndi:comp/env的组件用名称查找环境变量所有环境变量都由它们的容器在JNDI上下文中注册
环境变量的值是环境变量应取的值格式是字符串除了表示单个字符的类型javalangCharacter以外允许作为环境变量的所有类型都有以串作为参数的构造函数Enventryvalue tag包含了用于值的构造函数的串
环境变量的类型是环境变量值的类型类名必须是下面的类型之一
ljavalangBoolean
ljavalangByte
ljavalangCharacter
ljavalangDouble
ljavalangFloat
ljavalangInteger
ljavalangLong
ljavalangShort
ljavalangString
SMTP主机例子中的环境变量可以象下面这样
<enventry>
<description>
Enter the host name for sending email
</description>
<enventryname>SMTP Host Name</enventryname>
<enventryvalue>
homerspringfieldmaus
</enventryvalue>
<enventrytype>javalangString</enventrytype>
</enventry>
<enventry>
<description>SMTP port number for email
</description>
<enventryname>SMTP Port</enventryname>
<enventryvalue></enventryvalue>
<enventrytype>javalangInteger</enventrytype>
</enventry>
<enventry>
<description>
User authentication for SMTP server
</description>
<enventryname>SMTP User</enventryname>
<enventryvalue>bart</enventryvalue>
<enventrytype>javalangString</enventrytype>
</enventry>
<enventry>
<description>
Password for SMTP user
</description>
<enventryname>SMTP Password</enventryname>
<enventryvalue>Doh!</enventryvalue>
<enventrytype>javalangString</enventrytype>
</enventry>
使用环境变量
要在代码中使用环境变量很简单用JNDI查找环境变量就行了注意要使方法Contextlookup的结果与适当的类型相配如下所示
try {
InitialContext ic = new InitialContext();
Context ctx = iclookup(java:comp/env);
String hostname =
(String)(ctxlookup(SMTP Host));
Integer port = (Integer)(ctxlookup(SMTP Port));
String user = (String)(ctxlookup(SMTP User));
String password =
(String)(ctxlookup(SMTP Password));
sendEmail(
emailText port hostname user password);
} catch (NamingException nex) {
}
环境变量与servlet初始化参数
在Web应用中可以用servlet初始化参数代替环境变量定制servlet的行为Servlet开发者在webxml中用initparam tag定义servlet初始化参数在servlet代码中用方法javaxservletGenericServletgetInitParameter访问servlet初始化参数servlet初始化参数的使用范围是定义它的servlet
那么对于具体的定制来说如何在环境变量和servlet初始化参数之间做出选择呢?这个问题的答案依赖于定制的自然范围就象全局变量的作用范围是程序的名称空间一样环境变量的作用范围是JNDI名称空间这将会导致组件之间的不必要的依赖当定制只影响一个servlet时servlet初始化参数是最好的选择当定制涉及多个组件时考虑使用环境变量
代码示例
这个技巧的代码示例有两个部分第一部分是servlet打印应用的所有环境变量这个servlet的最后用ContextlistBindings方法列出了所有绑定在JNDI上下文java:com/env中的环境变量下面的代码片断摘选于这个servlet的源代码
public void printEnvEntries(HttpServletRequest req
HttpServletResponse res)
throws IOException ServletException {
ressetContentType(text/html);
PrintWriter out = resgetWriter();
try {
InitialContext ic = new InitialContext();
NamingEnumeration ne =
iclistBindings(java:comp/env);
outprintln(
<HTML><HEAD><TITLE>Environment Entries</TITLE></HEAD>);
outprintln(
<BODY><TABLE BORDER=><TR><TH>Entry</TH> +
<TH>value</TH></TR>);
while (nehasMore()) {
Binding ncp = (Binding)nenext();
String objName = ncpgetName();
Object objObj = ncpgetObject();
outprintln(<TR><TD> + objName + </TD>);
outprint(
<TD> + objObjtoString() + </TD></TR>);
}
outprintln(</TABLE></BODY></HTML>);
} catch (Exception e) {
throw new ServletException(e);
}
}
这个方法对java:com/env中的每个对象迭代用table的形式打印出每个环境变量的名称和文字表示试一试部署这个应用看一看定义在部署描述符文件中的环境变量运行示例代码一节指导你如何部署应用
这个技巧的代码示例的第二部分是一个定制tagDateTagjava说明了如何利用环境变量使组件(本例中是定制tag)可以定制
DataTag是一个简单的tag页面开发者可以用这个tag打印服务器的日期和时间单独使用时(<t:date/> )它用标准格式打印出日期和时间如果用tag的格式属性定义了格式打印时就使用所定义的格式(标准类SimpleDateFormat定义了格式语法)
部署者可以通过符号名用环境变量定义一列日期/时间格式如果DateTag的格式属性值以$开始那么这个tag就查找这个属性命名的环境变量值的格式例如下面的环境变量就是在webxml中定义的
<enventry>
<enventryname>LongTimeDateFormat</enventryname>
<enventryvalue>
Date: EEEE d MMMM yyyy Time: kk:mm:ss z
</enventryvalue>
<enventrytype>javalangString</enventrytype>
</enventry>
示例JSP包含了下面的文字
The server date in Obtuse format is
<mytags:date format=$ObtuseTimeDateFormat/>
运行时显示的是
The server date in Obtuse format is
::EST
这意味着部署者可以在应用的部署描述符文件中定义一列共用日期格式应用