2005年9月26日,Sun公司和JSR154的专家组发布Servlet API的一个新的版本。在一般情况下,一个JSR的新版本仅仅包括对以前少数有名无实的规范进行去除更新。但这次,新版本中增加新的特征和变化,他们对Servlets的产生重要影响,使得Servlet的版本升到了2.5。
在这篇文章里,我主要谈谈Servlet2.5版本中的新特征。描述每一个变化,阐述那些必要变化产生的背景,并展示如何在基于Servlet的项目中利用这些变化。
事实上,这是我为JavaWorld提供的第六篇关于Servlet API更新资料的文章。这篇文章意在两个目的:从眼前来看,向你介绍Servlet的新特征。从长远来看,是展现Servlet变化的历史概要,这样当你基于老的Servlet API版本进行编码的时候,你可以正确地决定哪些特征和功能你可以使用,而哪些特征和功能你不应该使用。你可以参考我先前写的关于Servlet的文章。
注意:当你想实践这些Servlet的新特征和功能时,你要知道的是:并不是所有的Servlet容器和Java企业级应用服务器都能立即适用于最新版的Servlet API,写这篇文章时(2006年1月2日),Jetty 6 server和Sun公司的GlassFish server是公认最好的支持Servlet2.5的容器,而Apache Tomcat5.5和Jboss 4.0目前只支持Servlet2.4。
Servlet2.5一些变化的介绍:
1) 基于最新的J2SE 5.0开发的。
2) 支持注释。
3) web.xml中的几处配置更加方便。
4) 去除了少数的限制。
5) 优化了一些实例
J2SE 5.0的产物:
从一开始,Servlet 2.5 规范就列出J2SE 5.0 (JDK 1.5) 作为它最小的平台要求。它使得Servlet2.5只能适用基于J2SE 5.0开发的平台,这个变动意味着所有J2SE5.0的新特性可以保证对Servlet2.5程序员有用。
传统意义上,Servlet和JEE版本一直与JDK的版本保持同步发展,但是这次,Servlet的版本跳过1.4版本。专家组认为版本的加速增长是正当的,因为J2SE5.0提出一个引人注目的,Servlet和JEE规范都要利用的特征??注释。
注释:
注释是作为JSR175的一部分提出的(一种为Java语言设计提供便利的Metadata)一种新的语言特色。它是利用Metadata为Java编码结构(类,方法,域等等)装饰的一种机制。它不能像代码那样执行,但是可以用于标记代码,这个过程是基于Metadata信息的代码处理机,通过更新他们的事件行为来实现的。
我们可以凭借不同的技巧来注释类和方法,例如连续地标记接口或者是@deprecated Javadoc评论。这种新式的Metadata可以便利地提供了一种标准的机制来实现注释功能,以及通过库来创建用户自己的注释类型的变量。
下面是一个简单的Web service 注释例子:
import javax.jws.WebService;
import javax.jws.WebMethod;
@WebService
public class HelloWorldService {
@WebMethod
public String helloWorld() {
return "Hello World!";
}
}
@WebService和@WebMethod这两个注释类型,在JSR181(为Java平台提供的Web ServicesMetadata)有详细说明,可以像类一样的引用,标记这个类作为一个Web service并且标记它的helloWorld()方法做为一个Web service方法。对于他们本身来说,注释只是写在那里并没有什么作用,好像在岗位上做记录一样,但是,一个容器一旦加载这个类并对那些注释进行二进制编码,就可以把这个类连到Web service上。
注释可以接受属性/值这些参数。它保存着参数的信息并且可以利用这些参数来更改被请求的事件行为。例如下面更高级的注释例子:
@WebService(
name = "PingService",
targetNamespace=http://acme.com/ping
)
@SOAPBinding(
style=SOAPBinding.Style.RPC,
use=SOAPBinding.Use.LITERAL
)
public class Ping {
@WebMethod(operationName = "Foo")
public void foo() { }
}
一旦加载了这个类,一个正确配置的容器就会识别出注释及其参数,并将这个做为一个PingService通过利用remote-procedure-call/literal的编码方式与一个Foo operation相连。实际上,注释便指明了类和类的容器之间的联系。
Java本身的规范(JSR175)仅仅有少量的注释类型变量。而这些有趣的注释类型变量主要来自于其他的JSRs:
•JSR 250: Java平台的公共注释
•JSR 220: 企业级JavaBeans 3.0
•JSR 224: 基于XML的Java API Web Services (JAX-WS) 2.0
•JSR 181: Java平台的Web Services Metadata
Servlet2.5中的注释:
回到Servlet2.5上来,一种新的规范描述了几种注释在Servlet环境中是如何工作的。功能弱的Servlet容器忽略了这些规范,然而JEE容器中的Servlet却严格遵守这些规范。
有的注释提供了在XML注册的可选择性,否则就要注册在配置文件web.xml中。有的作为容器的请求来执行其任务,否则就由Servlet亲自来执行。还有的注释两者都具备。
注释准确的定义不是完全固定的,因为Servlet本身并没有定义注释。它仅仅解释了它们如何影响Servlet环境,下面是注释的一个简要的概述,你可以看到在JEE5中它们的用途:
•@Resource and @Resources:@Resource位于类或变量中以对Servlet容器进行“资源注入”。当容器识别出这个注释时,它会在获得服务地位之前,用适当的值实现带注释的变量的重新注入。通过使用这种注释,你不必利用JNDI来查找命令和在配置文件web.xml中手动声明资源。服务器通过Servlet的自我调整来执行它的任务。变量的名称和类型由映像机制自动确定,尽管你可以利用注释的参数来超越这一限制。一个注入的资源可以是数据源,Java信息服务目的文件或者是环境设置的标量。下面是一个例子:
@Resource javax.sql.DataSource catalog;
public getData() {
Connection con = catalog.getConnection();
}
现在,在这段Servlet代码变成服务之前,容器会定位JNDI变量,并对于目录变量进行手动分配。
为了效率,仅仅某些类支持资源注入,这些类有:Servlets,Servlet过滤器,Servlet事件监听器,JSP标签操作器,JSP库事件监听器,用于处理beans的JSF,以及一些与Serlvets无关的类。
•@Resources注释与@Resource相似,但是它用于一组@Resource注释。它们都来自JSR250,是Java平台的公共注释。
•@PostConstruct and @PreDestroy:可以使方法成为带有生命周期的方法。@PostConstruct方法用于资源注入初始化之后。@PreDestroy方法用于Servlet脱离服务并释放注入的资源的时候。回收的方法必须是事实的方法,返回void并且不可以抛出任何异常。这些注释本质上使得任何方法都成为init()和destroy()的子方法,这些特征也来自与JSR250。
•@EJB:类似于@Resource,设计用于注入企业级的JavaBeans。比起@Resource,它略有不同,在于@EJB的参数特定设计用来定位EJB的参数。这个注释来自EJB3.0的规范。
•@WebServiceRef:与@Resource 和 @EJB相似,设计用于注入Web service参数。来自于JAX-WS2.0规范。
•@PersistenceContext, @PersistenceContexts, @PersistenceUnit, and @PersistenceUnits:这些注释来自EJB3.0规范来支持Java对象的持久化。
•@DeclareRoles: 定义应用程序中安全角色的使用。当定义一个Servlet类时,在配置文件web.xml中<security-role>标签中对它进行设置,来自JSR250。
• @RunAs:用于声明哪个类应该执行。当定义一个Servlet类时,在配置文件web.xml中<run-as>标签中对它进行设置。来自于JSR250。
注释的执行:
不论你使用注释与否??尤其在你不使用时??它对于理解服务器上程序的执行有着重要意义。为了让服务器识别类中的注释,它必须加载这些类,这就意味着服务器必须是启动着的,服务器通过WEB-INF/classes目录下和WEB-INF/lib目录下的所有类文件来查找注释。(每个规范下,服务器不必查找这两个目录以外的目录。)你可以通过下面的方法指明<web-app>根的属性而不必使用如何进行注释:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
version="2.5" full="true">
</web-app>
web.xml的便利:
Servlet2.5对于web.xml引入几个小的变动,使得它更加方便。
Servlet名称的通配符化:
首先,当你写<filter-mapping>,你现在可以在<Servlet-name>标签中使用*号来代表所有的Servlets。而以前,你必须一次把一个Servlet绑定到过滤器上,像这样:
<filter-mapping>
<filter-name>Image Filter</filter-name>
<Servlet-name>ImageServlet</Servlet-name>
</filter-mapping>
现在,你可以一次绑定所有的Servlets:
<filter-mapping>
<filter-name>Image Filter</filter-name>
<Servlet-name>*</Servlet-name> <!?新特征 -->
</filter-mapping>
这有着很大用途,例如:
<filter-mapping>
<filter-name>Dispatch Filter</filter-name>
<Servlet-name>*</Servlet-name>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
映射的复合模式:
其次,当我们写<Servlet-mapping> 或者 <filter-mapping>时,你现在可以在同一的标签中采用复合匹配的标准。以前一个<Servlet-mapping>只支持一个<url-pattern>元素,现在它不只支持一个,例如:
<Servlet-mapping>
<Servlet-name>color</Servlet-name>
<url-pattern>/color/*</url-pattern>
<url-pattern>/colour/*</url-pattern>
</Servlet-mapping>
同样地,以前<filter-mapping>也是只支持一个<url-pattern> 或者一个 <Servlet-name>。现在它对于每个元素都可以支持任意多个:
<filter-mapping>
<filter-name>Multipe Mappings Filter</filter-name>
<url-pattern>/foo/*</url-pattern>
<Servlet-name>Servlet1</Servlet-name>
<Servlet-name>Servlet2</Servlet-name>
<url-pattern>/bar/*</url-pattern>
</filter-mapping>
HTTP方法名:
最近,你可以将合法的HTTP/1.1方法名放进<http-method>元素中。当你使用这些方法时,<http-method>将指明<security-constraint>标记里的方法应该被应用。从以前来看,它仅限于HTTP/1.1的7个标准方法:GET,POST,PUT,DELETE,HEAD,OPTIONS和TRACE。但是,HTTP/1.1允许对方法进行扩展,WebDAV是用于这种扩展的普遍技术。在Servlet2.5中,你可以安全地约束任何可能的HTTP方法名,标准及扩展,包括WebDAV方法,例如:LOCK,UNLOCK,COPY及MOVE。
如果你写一个WebDAV的Servlet,你不必使用doLock()和doCopy()方法。你必须写自己的service()方法及分派request.getMethod()方法。正由于这种变化,你不必管理系统的安全性。
去除限制:
Servlet2.5去除了关于错误处理和回话跟踪的一些限制。对于错误处理,Servlet2.5之前,配置在<error-page>中的错误处理页面不能通过调用setStatus()方法来修改触发他们的错误代码,而Servlet2.5减弱了这一规范。这样的规范的产生于这样的观点,就是错误页面的工作是指出每个错误而不是修改错误。但是,实际使用中,错误页面不只是用于指出错误,而是还能做更多的事情,或许可以代替在线帮助来帮助用户解决问题。这个规范将不再限制错误页面所产生的反馈信息。
对于会话跟踪,Servlet2.5之前,调用RequestDispatcher.include()的Servlet不能设置响应的标题头,而Servlet2.5减弱了这一规范。原规范的目的是使内部的Servlets限制在自己的页面空间中,不可以影响外部的页面。现在这个规范已经减弱,允许在内部的Ser