技术开发 频道

强大的功能、高生产率和低复杂性

  本节通过几个示例展示 Java EE 5 中的简化编程模型,说明这些模型如何提高开发人员的生产率。您可以看到如何通过这些模型快速开发一个示例应用程序,这个程序包含一个 Web 服务端点和客户机,使用 EJB 实现业务逻辑,使用 JSF 作为 Web 前端。

  我将使用一个简单的 Web 应用程序演示 Java EE 5 技术,这个程序是一个称为 RideSynergy 的虚构的服务(下载 中提供了源代码)。RideSynergy 服务帮助人们在网上安排合作用车。我使用 NetBeans 5.5 开发这个服务,并在 Sun Application Server 9.0_01 和 WebSphere Application Server(Community Edition)2.0 上测试过。

  RideSynergy 的工作方式如下:

  它通过一个 Web 页面接受车辆供应和请求。

  如果用户提供车辆,它会显示匹配的车辆请求列表。

  如果用户请求车辆,它会显示匹配的车辆供应列表。

  为了方便用户,它会在显示车辆供应和请求结果时显示天气预报,因为天气可能影响用户的决定。

  它以 Web 服务的形式向第三方应用程序提供关于供应和请求的统计数据。

  访问 RideSynergy 的用户使用图 1 所示的页面提供或请求车辆,需要指定旅行起点和终点的 ZIP 编码并输入一个电子邮件地址。这个页面还提供查看当地天气报告的选项。

  图 1. RideSynergy 供应和请求页面

  如果提交一个车辆供应,结果页面(见图 2)会列出匹配的所有车辆请求。如果提交一个车辆请求,会列出匹配的供应。只有在供应和请求页面上选择 Check weather 复选框,才会显示天气预报(注意,在实际的应用程序中,显示五天的天气预报数据。为了简单,图 2 被截短了)。天气预报数据是从一个公共 Web 服务(http://www.webservicex.net)获得的。

  图 2. RideSynergy 结果页面

  RideSynergy 背后的代码展示了 Java EE 5 的简单 Web 服务编程模型:它使用 JAX-WS 建立一个 Web 服务端点定义(其中包含一个注解),并用 wsimport 特性创建一个 Web 服务客户机。它还展示了 Java EE 5 中的简单 EJB 编程模型和 JSF 的基本原理。

  注解:用更少的代码做更多工作

  RideSynergy 以 Web 服务的形式提供统计数据,这个特性很好地说明了 Java EE 5 让我们能够用更少的代码做更多工作。这个特性是在 RideStatistics 类中实现的,它演示了最简单的 Java EE 5 注解形式。但是,简单并不意味着功能不强:它们说明,与 J2EE 1.4 方式相比,用 Java EE 5 方式实现这些特性要简单得多。

  清单 1 中的 RideStatistics 类实现一个 Web 服务,它使用无状态 RideManagerBean 会话 bean,根据 Web 服务客户机指定的起点和终点 ZIP 编码查询匹配的车辆供应数量。RideManagerRemote 接口定义 RideManagerBean 上可供客户机代码使用的操作,客户机代码可以在同一个 JVM 中运行,也可以在其他 JVM 中运行。

  清单 1. RideStatistics Web 服务

1 package com.ridesynergy;
2
3   import java.util.Set;
4
5   import javax.ejb.EJB;
6
7   import javax.jws.WebService;
8
9   /**
10
11   * Web Service that exposes a count of ride offers made to and from specific
12
13   * ZIP codes.
14
15   *
16
17   * @author smoore
18
19   */
20
21   @WebService
22
23   public class RideStatistics {
24
25   @EJB
26
27   RideManagerRemote rideManager;
28
29   /** Creates a new instance of RideStatistics */
30
31   public RideStatistics() {
32
33   }
34
35   public Integer rideOffersFromZipCode(Integer zipCode) {
36
37   Set
38
39   return new Integer(results.size());
40
41   }
42
43   public Integer rideOffersToZipCode(Integer zipCode) {
44
45   Set
46
47   return new Integer(results.size());
48
49   }
50
51   }
52
53

  清单 1 包含两个注解:@WebService 和 @EJB。首先,我要讨论如何通过 @EJB 注解用依赖项注入(dependency injection) 技术访问 EJB。然后讨论如何通过 @WebService 注解将一个 POJO 变成完整的 Web 服务端点。

  依赖项注入

  如果您熟悉 J2EE 1.4 中的 EJB 编程,那么在看到 清单 1 时可能会问:真的 这么容易就获得了一个 EJB 的引用吗?是的,因为 @EJB 注解提供了一种基于依赖项注入的简单编程模型。

  有了 @EJB 注解,就不再需要编写 J2EE 1.4 中的那些复杂代码(比如清单 2 中的代码):

  清单 2. Java EE 5 之前的 RideManagerBean 客户机

1 . . .
2
3   Context initial = new InitialContext();
4
5   Context myEnv = (Context) initial.lookup("java:comp/env");
6
7   Object obj = myEnv.lookup("ejb/RideManager");
8
9   RideManagerHome home = (RideManagerHome) PortableRemoteObject.narrow(
10
11   obj, RideManagerRemote.class);
12
13   RideManager manager = home.create();
14
15   . . .
16
17

  在 Java EE 5 支持的 EJB 3.0 编程模型中,这个 @EJB 注解注入 RideStatistics 对 RideManagerRemote 的依赖项,这样 RideStatistics 就不需要用 JNDI 查找引用。

  它还避免了直接依赖于包含 RideManagerRemote 的包。看一下 import 语句;这里没有针对 RideManagerRemote 的 import 语句(但是,它却可以通过编译)。所以,可以将 RideManagerRemote 重构到另一个包中,而不需要更新和重新编译 RideStatistics。

  注解还给依赖项的另一方面带来许多好处:实际 EJB 提供 RideManagerRemote 背后的实现并告诉 Java EE 5 容器用它做什么。我将稍后解释。

  复杂的运行时行为

  当部署到 Java EE 5 容器时,JAX-WS 处理 清单 1 中的 @WebService 注解,并将 RideStatistics 类转换为一个完整的 Web 服务端点,这个端点包含两个操作:rideOffersFromZipCode 和 rideOffersFromToZipCode。JAX-WS 处理提供 Web 服务所需的所有工作,包括生成 Web Services Description Language(WSDL),让 Web 上的其他应用程序能够发现并使用这个 Web 服务,还提供机制响应对 Web 服务的客户机请求。

  JAX-WS 为 RideStatistics Web 服务生成 WSDL 的默认位置是 http://server:port/ridesynergy2-war/RideStatisticsService?WSDL。按照以下步骤查看这个 WSDL:

  下载 RideSynergy 企业存档文件 ridesynergy2.ear(见 下载)并将它部署到 Java EE 5 容器中。

  将默认位置中的 server 和 port 值替换为容器的主机名和端口。

  在浏览器中访问这个位置。

  更复杂的注解

  清单 1 中的注解只是简单的注解。注解还可以接受命名元素(named element),这种元素与方法参数相似,但是参数的次序和数量不重要,因为每个参数都有名称。使用命名元素就像是将一个映射传递给注解,其中包含的键/值对可以决定处理注解的方式。

  WeatherForecastSoap 接口(见清单 3)是由 JAX-WS 中的 wsimport 工具创建的,其中包含接受命名元素的注解。清单 3 给出 WeatherForecastSoap 接口:

  清单 3. WeatherForecastSoap 接口

1 . . .
2
3   @WebMethod(operationName = "GetWeatherByZipCode",
4
5   action = "http://www.webservicex.net/GetWeatherByZipCode")
6
7   public WeatherForecasts getWeatherByZipCode(
8
9   @WebParam(name = "ZipCode",
10
11   targetNamespace = "http://www.webservicex.net")
12
13   String zipCode);
14
15   . . .
16
17

  在清单 3 中,getWeatherByZipCode() 方法上有一个 @WebMethod 注解,这个注解有两个命名元素:operationName 和 action。getWeatherByZipCode() 的 zipCode 参数上有一个 @WebParam 注解,这个注解包含命名元素 name 和 targetNamespace(注意在实际应用程序中,getWeatherByZipCode() 还有其他注解,这里省略掉了)。

  定义注解的代码指定注解接受哪些命名元素(如果有的话)。细节参见 参考资料 中的注解初级教程链接。

  声明无状态会话 bean

  清单 4 给出 RideManagerBean 的类声明,这个无状态会话 bean 实现了 清单 1 所示的 RideManagerRemote 接口:

  清单 4. 无状态会话 bean 声明

1 . . .
2
3   @Stateless
4
5   public class RideManagerBean implements RideManagerRemote {
6
7   . . .
8
9

  在 J2EE 1.4 中,EJB 必须实现 SessionBean 接口,这个接口要求实现六个方法。在许多情况下,这些方法实现都是空的,它们之所以存在只是为了满足接口的要求,让代码能够通过编译,这使代码很杂乱。EJB 3.0 通过提供生命周期注解 @PostConstruct、@PreDestroy、@PostActivate 和 @PrePassivate 消除了这种混乱。可以根据需要将这些注解添加到适当的方法上,从而实现对生命周期事件的响应;只要求这些方法是公共方法,没有参数并返回 void。

  用注解替代部署描述符

  Java EE 5 中的注解还可以消除以前的 Java EE 版本所需的大量配置代码。例如,清单 4 中的 @Stateless 注解可以替代 EJB 部署描述符,EJB 部署描述符是一个 XML 配置文件,它向容器提供 EJB 的细节。在以前的 Java EE 平台中,必须在一个符合 EJB 2.1 模式的 XML 文件中包含这样的描述符。清单 5 给出配置 RideManagerBean 和所需接口的代码片段:

  清单 5. Java EE 5 以前的部署描述符

1 <display-name>RideManagerJAR</display-name>
2 <enterprise-beans>
3    <session>
4       <ejb-name>RideManagerBean</ejb-name>
5       <home>com.ridesynergy.RideManagerHome</home>
6       <remote>com.ridesynergy.RideManager</remote>
7       <ejb-class>com.ridesynergy.RideManagerBean</ejb-class>
8       <session-type>Stateless</session-type>
9       <transaction-type>Bean</transaction-type>
10       <security-identity>
11           <use-caller-identity/>
12       </security-identity>
13    </session>
14 </enterprise-beans>
15

  Java EE 5 向后兼容以前的 EJB 部署描述符。如果愿意,甚至可以混合使用这两种方式,让遗留代码用描述符指定 EJB,而用注解声明新的 EJB。

  除了减少所需的代码量之外,注解还在维护方面有好处,因为配置信息就放在源代码中,Sun 的架构师 Graham Hamilton 将这称为 “truth-in-source-code”对于正确地加上注解的类,不需要同时查看源代码和配置文件,就能够理解其运行方式,因为注解在源代码中直接定义了特殊行为。

  在 Roland Barcia 的文章 “了解 Java EE 5” 中,通过许多示例展示了 Java EE 5 中的注解如何简化应用程序开发。

  合理的默认行为

  我们只添加了一个简单的注解,就把 RideStatistics 变成了一个 Web 服务,这也展示了另一个 Java EE 5 设计原则:提供合理的默认行为,从而使编程模型更简单。

  在这个示例中,JAX-WS 假设在带 @WebService 注解的类中所有公共方法都应该转换为 Web 服务操作,并以方法名作为操作名。在处理这些方法的输入参数和输出参数时,也会做相似的假设。如果默认行为不适合您的需要,那么可以通过在方法上加注解来修改。但是在许多情况下,都希望 Web 服务中使用的名称与实现 Web 服务的类匹配,所以 JAX-WS 的默认行为是很合理的,这大大简化了 Web 服务的开发。

  结束语

  在过去,Java EE 技术虽然很强大,但是也很麻烦;开发人员必须忍受它的复杂性,或者使用开发工具 “驯服” 它,才能享受到它的好处。这让大家觉得使用 Java EE 非常累人,只有在大型的企业级平台确实需要它的强大特性,而且组织拥有能够应付 Java EE 开发的资源的情况下,才会考虑使用这种平台。

  Java EE 5 试图消除这种坏名声,使它成为适合企业应用程序开发的强大且易用的平台,采取的措施包括提供注解等新的语言特性,采用合理的默认行为等设计目标,以及强调更简单的编程模型。另外,更简单的编程模型减少了不必要的复杂性,降低了开发人员对第三方工具的需求。因此,开发强大的企业应用程序的成本现在显著降低了。开发人员花在与平台 “搏斗” 上的时间更少了,可以集中更多精力开发需要的实际功能,开发速度大大提高了。

  以前被 Java EE 技术吓退的开发团队应该重新审视 Java EE 5,现有 J2EE 应用程序的开发人员和维护人员应该研究 Java EE 5 中的众多特性,从而使自己的工作更轻松。

  代码下载:j-jee5.zip j-jee5.ear

0
相关文章