了解 Java EE 5

重要增强功能意味着更快、更容易、更简单地开发企业应用程序

developerWorks
文档选项
将打印机的版面设置成横向打印模式

打印本页

将此页作为电子邮件发送

将此页作为电子邮件发送



级别: 中级

Roland Barcia (barcia@us.ibm.com), IT 咨询专家, IBM WebSphere 软件服务部

2007 年 11 月 01 日

概要介绍新的 Java™ EE 5 规范、它的许多重要增强功能以及它对 WebSphere® 应用程序的意义。

引言

纵 观 Java Platform, Enterprise Edition (Java EE) 规范的历史可以看出,每次重大修订都是由一个重要主题推动的。例如,第一次发布 J2EE™ 1.2 时,伴随的重要主题是首次将单独的规范绑定在一起,后来,在 J2EE 1.4 中,关注的重要主题则是 Web 服务。图 1 显示了 Java EE 的摘要历史,列出了每个版本的重要功能以及促成每次修订的一些重要外部影响。


图 1. Java EE 的历史
图 1. Java EE 的历史

与一些新技术的大多数早期版本一样,Java EE 规范的以前版本中存在一些“难点”,其中包括:

  • 业务逻辑编程的复杂性。
  • 持久性编程模型的复杂性和性能。
  • 表示层/逻辑混合。
  • Web 服务的类型、复杂性、文档模型、扩展和性能。
  • 多成员团队开发。
  • 漫长的编辑-编译-调试周期。

这时,毫无疑问,Java EE 5 规范的主题就是简化,这一目标已通过改善以下领域的开发体验得到实现:

  • 简化业务逻辑开发。
  • 简化测试和依赖关系管理。
  • 简化 O/R 持久性。
  • 增强 Web 服务编程模型。

Java EE 5 中的许多升级都受到商业和开放源代码领域创新技术的影响,例如 Hibernate、Spring、Service Data Object (SDO) 以及其他技术。另外,还预期对规范的级别进行升级,做一些小幅度的改进。

为 您使用 Java EE 5 做准备,本文重点介绍新规范的一些主要功能,如 EJB 3.0、Java Persistance Architecture (JPA)、Web 服务、JAX-WS 及其他一些内容,然后简单地介绍我们对 Java EE 6 的一些可能的预期。





回页首


EJB 3.0

对于 Java EE 5 中的所有技术增强而言,Enterprise JavaBean™ (EJB) 3.0 是最为显著的,已对它的外观进行了很大的更改,明显简化了开发。EJB 3.0 规范已拆分为三个子规范:

  • EJB 3.0 简化 API:定义用于编码 EJB 组件(特别是会话 Bean 和消息驱动的 Bean)的新简化的 API。

  • 核心契约和要求:定义 Bean 和 EJB 容器之间的 EJB 契约。

  • Java 持久性体系结构 API:为持久性定义新实体 Bean 模型。

下一部分描述 EJB 3.0 和 JPA API 的更新。

EJB 3.0 简化

POJO (传统 Java 对象)是最近经常提到的一个术语,它是指编写为简单 Java 类的代码。由于 EJB 2.x 程序要求您扩展特定的类、提供多个接口并编写部署描述符,因此它们被视为“重载”的 Java 对象,而不再是简单的对象;而且,还需要 J2EE 容器来运行和测试它们。EJB 3.0 的更改包括:

  • EJB 组件不再要求主接口。另外,不再需要 EJB 组件提供不同的接口或扩展任何特定于 EJB 的类。

  • J2SE 5.0 标注现在是实现 EJB 3.0 组件的一个主要辅助方法。通过指定特殊的标注,开发人员可以创建 EJB 组件的 POJO 类,并将其作为 XML 的备选方案。

  • EJB 3.0 引入了业务接口概念,而非单独的远程和本地接口。下面给出了它的一个示例:

    清单 1

                                
    public interface Stock
    {
    public double getQuote(String symbol);
    }

    您的 Bean 类可以实现以下接口:

    清单 2
                                
    @Stateless public class StockBean implements Stock
    public double getQuote(String symbol)
    {
    return 100.33;
    }
    }

    在上面的示例中,@Stateless 标注意味着此类现在是一个无状态的会话 Bean,并且使用业务接口来调用它。还可以在不实现特定接口的情况下对无状态会话 Bean 进行编码,而且可以通过容器生成一个:

    清单 3
                                
    @Stateless public class StockBean
    public double getQuote(String symbol)
    {
    return 100.33;
    }
    }

    缺省情况下,除非特别标注,否则,所有公共方法都包括在业务接口中。例如,如果使用 @BusinessMethod 至少指定一个方法,则只有使用 @BusinessMethod 指定的方法才包括在业务接口中:

    清单 4
                                
    @Stateless public class StockBean
    @BusinessMethod public double getQuote(String symbol)
    {
    return 100.33;
    }
    }

    现在已经创建了一个接口,那么如何指定一个方法是远程的还是本地的?当然,可以使用一个标注:

    清单 5
                                
    @Stateless public class StockBean
    @Remote public double getQuote(String symbol)
    {
    return 100.33;
    }
    }

    您可以标注业务接口或者 Bean 类本身。当选择生成业务接口时,在 Bean 类上启用标注非常有用。

EJB 3.0 规范的更新包括以下内容:

  1. 容器服务
  2. 回调
  3. 拦截器
  4. 依赖项注入
  1. 容器服务

    EJB 组件由于隐式支持事务管理和安全性,因此非常受欢迎。EJB 3.0 规范使用标注(和 XML)来应用容器服务。下面给出了一个示例,介绍如何在无状态会话 Bean 上指定事务属性。

    清单 6

                                
    @Stateless public class StockBean
    {

    @TransactionAttribute(TransactionAttributeType.REQUIRESNEW)
    public double getQuote(String symbol)
    {
    return 100.33;
    }
    }

    此标注意味着,该方法将在新事务中运行。请参见规范,了解不同标注的具体语法和语义,但相同事务和安全功能都有标注。还可以使用 XML 部署描述符应用容器服务,而XML 部署描述符可以在部署时覆盖启用灵活性的标注。
  2. 回调

    回 调是什么情况?在 EJB 3.0 之前,必须在 Bean 类上实现回调方法,如 ejbCreate();Bean 类必须实现所有方法,无论是否使用它们。在大多数情况下,这些方法实现是空的。现在还通过标注并使用回调方法或回调侦听器类处理回调。下面是一个示例,说 明如何编写代码来使用回调方法响应回调:

    清单 7

                                
    @Stateless public class StockBean implements Stock
    public double getQuote(String symbol)
    {
    return 100.33;
    }

    @PostConstruct initializeCache()
    {
    }
    }

    以上代码可让您在创建 Bean 实例之后实现代码。如果希望使用回调侦听器,则可以创建回调侦听器类:

    清单 8
                                
    public class MyCallbackListener
    {
    @PrePassivate public clearCache(Object obj)
    {
    Stock stock = (Stock) obj;
    //perform logic
    }
    }

    不属于 Bean 类的回调类必须获取 java.lang.Object 参数。容器然后传递 Bean 实例。Bean 类通过使用特殊回调标注在 Bean 类级别添加回调侦听器类:

    清单 9
                                
    @CallbackListener MyCallbackListener
    @Stateless public class StockBean implements Stock
    public double getQuote(String symbol)
    {
    return 100.33;
    }
    }

    回调方法比较好,因为在代码中包括回调方法是有条件的,这与实现接口不同。
  3. 拦截器

    EJB 规范另一增强功能是使用拦截器。EJB 组件以前缺少的功能是无法对预处理/后处理和横切关注点(与 Servlet 筛选器对 Servlet 的作用类似)等内容执行面向方面的开发 (AOP)。现在可以开发一个拦截器类并将其应用到 Bean。下面是一个审核 StockBean 类调用的拦截器类的示例:

    清单 10

                                
    public class StockRequestAudit {
    @AroundInvoke
    public Object auditStockOperation(InvocationContext inv) throws
    Exception {
    try {
    Object result = inv.proceed();
    Auditor.audit(inv.getMethod().getName(), inv.getParameters[0]);
    return result;
    } catch (Exception ex) {
    Auditor.auditFailure(ex);
    throw ex;
    }
    }
    }

    上 面的拦截器拦截对目标 EJB 方法的调用,然后调用 InvocationContext 上的 proceed() 方法。这可让该调用方法流经实际被调用的 EJB 方法。在返回目标 EJB 方法之后,它使用 InvocationTarget 中的元数据来获取被调用的目标 EJB 组件的方法名和参数。然后可以将拦截器应用到 Bean 类:

    清单 11
                                
    @Stateless @Interceptors({StockRequestAudit})
    public class StockBean implements Stock
    public double getQuote(String symbol)
    {
    return 100.33;
    }
    }

    另 外,还可以开发一个在 Bean 类内部实现的拦截器方法,而且可以指定多个拦截器,在指定多个拦截器时,它们的调用顺序由其在 Bean 类中定义的顺序指定。还可以使用 XML 在 Bean 以外应用拦截器,这在 AOP 中为首选方法,因为您希望向 Bean 透明地应用横切关注点。
  4. 依赖项注入

    依 赖于数据源之类的 EJB 代码依赖项和 EJB 客户端调用 EJB 组件的方式难以进行 EJB 开发测试。为解决此问题,EJB 3.0 规范引入了依赖项注入机制。EJB 没有使用 JNDI 查找,而是通过注入代码定义一个资源引用。下面是 EJB Bean 的一个示例,此 EJB Bean 需要调用另一个 EJB 组件并使用数据源执行 JDBC 工作:

    清单 12

                                
    @Stateless public class StockBean implements Stock
    {
    @EJB(name="MarketBean", businessInterface="Market")
    Market market;

    @Resource(name="StockDB, resourceType="javax.sql.DataSource")
    DataSource stockDS

    public double getQuote(String symbol)
    {
    Connection con = stockDS.getConnection();
    //DO JDBC work

    return market.getCurrentPrice(symbol);
    }
    }

    依赖项注入可以通过多种方式进行,例如通过 setter 方法或类变量。有关详细信息,请参见规范

Java 持久性体系结构 (JPA)

EJB 持久性的规范已发生了显著变化。该规范称为容器管理的持久性 (CMP),它没有定义映射层,而是由容器映射;因此它由供应商实现映射。受多个商业和开源产品和技术(如 Hibernate、Java Data Objects (JDO) 和 TopLink)的影响,EJB 3.0 引入了新的持久性样式,即基于 POJO 的持久性:

  • 在成功模式上建模。
  • 简化 JDBC 访问模式。
  • 可以与 Web 服务集成。
  • 不受容器的阻碍;可以在 Java EE 或 Java SE 环境中使用 JPA。
  • 标准化 O/R 映射元数据。
  • 支持自顶向下、中间相遇和自底向上的开发。
  • 支持断接和连接的对象状态,省去了对单独的数据传输对象的需要。图 2 显示了一个示例。

图 2. 支持对象状态
图 2. 支持对象状态

JPA API 的更新包括以下内容:

  1. 类型:实体和表
  2. 实例:Java 对象
  3. 属性:Java 属性和列标注
  4. 依赖对象:嵌入式 Java 对象
  5. 派生属性:瞬态标注
  6. 键属性:标注的字段和键类
  7. 关系:标注和联合列
  8. 约束:标注和数据库
  9. 继承:标注——单个表、联合表和按类表
  1. 类型:实体和表

    JPA 的类型是实体(不再称为实体 Bean),这些实体可以映射到表。映射的主要机制是通过标注实体类。下面是客户 Java 对象和 CUSTOMER 表之间的一个映射示例:

    清单 13

                                
    @Entity
    @Table(name="CUSTOMER")
    public class Customer implements Serializable {
    ...

    类被标注为一个实体并使用客户标注。部署描述符可用作备用或覆盖机制。
  2. 实例:Java 对象

    应 用程序在运行时与 Java 对象交互。通过使用称为实体管理器的特殊对象,应用程序可以查询或保持对象。使用 EJB 容器中的依赖项注入将实体管理器注入到应用程序(在 Java SE 环境中也可以通过 EntityManagerFactory 查找)。下面是一个示例:

    清单 14

                                
    @PersistenceContext (unitName="db2")
    private EntityManager em;

    应用程序可以检索对象或者将它们传递到实体管理器。下面是使用实体管理器通过主键查找对象的应用程序示例:

    清单 15
                                
    Customer customer = (Customer)em.find(Customer.class,customerId);

    下面是另一个示例,说明创建 Java 对象,并通过将其传递到实体管理器而保存到数据库:

    清单 16
                                
    CustomerOrder newOrder = new CustomerOrder();
    newOrder.setStatus("OPEN");
    newOrder.setTotal(new Integer(0));
    newOrder.setCustomerId(customerId);
    em.persist(newOrder);

  3. 属性:Java 属性和列标注

    属性是类中的 Java 属性。Java 属性可以通过 @column 标注映射到数据库列。共有两种属性映射形式:字段或属性(缺省):

    清单 17

                                
    @Entity(access=FIELD)
    @Table(name="PRODUCT")
    public class Product implements Serializable {

    @Id
    @Column(name="SKU")
    Integer sku;

    @Column(name="DESC")
    String description;

    @Column(name="PRICE")
    Integer cost;

  4. 依赖对象:嵌入式 Java 对象

    JPA 支持依赖对象。可以创建一个特殊的可嵌入对象,可以通过使用 @Embeddable 标注类对其进行定义:

    清单 18

                                
    @Embeddable
    public class CustomerAddress {
    private int streetAddress;
    private String city;
    private String state;
    private String country;
    ...
    }

    然后可以将该对象定义为实体类上的一个字段:

    清单 19
                                
    @Entity
    @Table(name="CUSTOMER")
    public class Customer {
    private String name;
    private CustomerAddress ca;

    @Embedded
    @AttributeOverrides({
    @AttributeOverride(name="streetAddress", column=@Column("
    STRT_ADD")),
    @AttributeOverride(name="city", column=@Column("CITY"))
    ... //more
    })
    public CustomerAddress getCustomerAddress()
    {

    ...
    }

    使用特殊的属性覆盖,可以将可嵌入类的字段映射到实体中。备用方法是直接将列映射到可嵌入类。
  5. 派生属性:瞬态标注

    缺省情况下,所有字段在 JPA 中都是持久性的;但是,您可以将一个字段标注为瞬态的,然后可以使用逻辑派生任何字段。下面是执行派生字段的查询:

    清单 20

                                
    @Transient
    public Integer getTotal() {

    Query totalLineItems = em.createNamedQuery("getOrderTotal");
    totalLineItems.setParameter("orderId",orderId);
    Integer result = (Integer)totalLineItems.getSingleResult();
    return result;
    }

  6. 键属性:标注的字段和键类

    JPA 支持多种主键以及各种键的生成。在下面的简单示例中,您可以使用 @Id 标注将实体上的字段标注为主键:

    清单 21

                                
    @Entity
    @Table(name="CUSTOMER")
    public class Customer implements Serializable {

    private Integer id;
    private String name;
    private CustomerOrder currentOrder;


    @Id
    @Column(name="CUST_ID")
    public Integer getId() {
    return id;
    }
    public void setId(Integer id) {
    this.id = id;
    }
    ...

    还可以为具有组合键的实体创建一个主键类:

    清单 22
                                
    public class LineItemId implements Serializable {

    private Integer orderId;
    private Integer productId;
    public LineItemId() {
    super();
    // TODO Auto-generated constructor stub
    }
    @Column(name="ORDER_ID")
    public Integer getOrderId() {
    return orderId;
    }
    public void setOrderId(Integer orderId) {
    this.orderId = orderId;
    }

    @Column(name="PRODUCT_ID")
    public Integer getProductId() {
    return productId;
    }
    public void setProductId(Integer productId) {
    this.productId = productId;
    }
    public boolean equals(Object arg0) {
    if (arg0 == this) return true;
    if (!(arg0 instanceof LineItemId)) return false;
    LineItemId other = (LineItemId)arg0;
    if(other.getOrderId().equals(orderId) &&
    other.getProductId().equals(productId))
    {
    return true;
    }
    return false;

    }
    public int hashCode() {
    return orderId + productId.hashCode();
    }

    }

    然后可以使用 @IdClass 标注在实体上定义组合键:

    清单 23
                                
    @Entity
    @Table(name="LINEITEM")
    @IdClass(LineItemId.class)
    public class LineItem implements Serializable {

    您的实体类必须在类上具有匹配字段,或者它可以作为可嵌入键嵌入该键:

    清单 24
                                
    @Entity
    @Table(name="LINEITEM")
    @IdClass(LineItemId.class)
    public class LineItem implements Serializable {
    private LineItemId lineItemId;

    @EmbeddedId
    public LineItemId getLineItemId()
    {
    return lineItemId;
    }

    ...

    另一个主要增强是支持生成主键。通过使用 @Id 标注的生成属性,可以选择一个不同的策略。例如,您可以选择向 DB2 标识列委派主键生成,如下所示:

    清单 25
                                
    @Id(generate=GeneratorType.IDENTITY)
    @Column(name="ORDER_ID")
    public Integer getOrderId() {
    return orderId;
    }
    public void setOrderId(Integer orderId) {
    this.orderId = orderId;
    }

    其他受支持机制包括序列和表生成。
  7. 关系:标注和联合列

    JPA 对实体之间的关系提供强大的支持。JPA 支持一对一、一对多、多对一和多对多关系。在 JPA 中,关系不是双向的,这与 EJB 2.x 中相同。相反,对象将其他实体声明为成员,并添加标注来定义关系。可以使用特殊属性将关系转换为双向的。下面是具有两个不同关系的 CustomerOrder 类的示例:

    清单 26

                                
    @Entity
    @Table(name="CUSTOMER")
    public class Customer implements Serializable {


    private Integer id;
    private String name;
    private CustomerOrder currentOrder;


    @Id
    @Column(name="CUST_ID")
    public Integer getId() {
    return id;
    }
    public void setId(Integer id) {
    this.id = id;
    }

    @Column(name="NAME")
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }

    @OneToOne(cascade=CascadeType.ALL , fetch=FetchType.EAGER )
    @JoinColumn(name="OPEN_ORDER_ID",referencedColumnName="ORDER_ID")
    public CustomerOrder getCurrentOrder() {
    return currentOrder;
    }
    public void setCurrentOrder(CustomerOrder currentOrder) {
    this.currentOrder = currentOrder;
    }

    }

    在 此关系中,通过在 Customer 类中标注 CustomerOrder 属性,将 Customer 与 CustomerOrder 定义为一对一关系。还定义了 JoinColumn 信息。名称属性在 Customer 类映射到的表上定义外键,参考列定义 Table CustomerOrder 映射到的主键。对关系的任何约束都定义为 @OneToOne 标注的属性。CustomerOrder 类如下所示。CustomerOrder 定义了一个 Customer 属性;不过 CustomerOrder 对象有一个返回到 Customer 的一对多关系。这是因为 Customer 只能有一个当前顺序;实际上,一个客户可以有多个顺序,因此 CustomerOrder 显示了这一点。不过,此处的 mappedBy 属性用于定义由 Customer 类将 CustomerOrder 映射到关系的另一侧。此类如下所示:

    清单 27
                                
    public class CustomerOrder implements Serializable {
    private Integer orderId;
    private String status;
    private Integer total;
    private Integer customerId;
    private Collection<LineItem> lineItems;
    private Customer customer;

    @Column(name="CUSTOMER_ID")
    public Integer getCustomerId() {
    return customerId;
    }
    public void setCustomerId(Integer customerId) {
    this.customerId = customerId;
    }

    @Id(generate=GeneratorType.IDENTITY)
    @Column(name="ORDER_ID")
    public Integer getOrderId() {
    return orderId;
    }
    public void setOrderId(Integer orderId) {
    this.orderId = orderId;
    }
    @Column(name="STATUS")
    public String getStatus() {
    return status;
    }
    public void setStatus(String status) {
    this.status = status;
    }
    @Column(name="TOTAL")
    public Integer getTotal() {
    return total;
    }
    public void setTotal(Integer total) {
    this.total = total;
    }

    @ManyToOne(fetch=FetchType.EAGER,optional=false)
    @JoinColumn(name="CUSTOMER_ID",
    referencedColumnName="CUST_ID",insertable=false,updatable=false,
    nullable=false,unique=true)
    public Customer getCustomer() {
    return customer;
    }
    public void setCustomer(Customer customer) {
    this.customer = customer;
    }
    @OneToMany(mappedBy="customerOrder", cascade=CascadeType.ALL ,
    fetch=FetchType.EAGER)
    public Collection<LineItem> getLineItems() {
    return lineItems;
    }
    public void setLineItems(Collection<LineItem> lineItems) {
    this.lineItems = lineItems;

    }

    }

    CustomerOrder 中的另一关系包含 LineItem 对象的集合。这是一个一对多关系。注意,JRE 5 定义泛型的使用,指定集合的类型。此处还使用了特殊的 mappedBy 属性,使关系的另一侧映射成为双向关系。

    清单 28
                                
    @Entity
    @Table(name="LINEITEM")
    @IdClass(LineItemId.class)
    public class LineItem implements Serializable {

    private Product product;
    private Integer orderId;
    private Integer productId;
    private Integer quantity;
    private Integer total;
    private CustomerOrder customerOrder;

    @Column(name="QUANTITY")
    public Integer getQuantity() {
    return quantity;
    }
    public void setQuantity(Integer quantity) {
    this.quantity = quantity;
    }

    @Column(name="AMOUNT")
    public Integer getTotal() {
    return total;
    }
    public void setTotal(Integer total) {
    this.total = total;
    }

    @ManyToOne(fetch=FetchType.EAGER,optional=false)
    @JoinColumn(name="PRODUCT_ID",
    referencedColumnName="SKU",insertable=false,updatable=false,
    nullable=false,unique=true)
    public Product getProduct() {
    return product;
    }
    public void setProduct(Product product) {
    this.product = product;
    }

    @Column(name="ORDER_ID")
    public Integer getOrderId() {
    return orderId;
    }
    public void setOrderId(Integer orderId) {
    this.orderId = orderId;
    }

    @Column(name="PRODUCT_ID")
    public Integer getProductId() {
    return productId;
    }
    public void setProductId(Integer productId) {
    this.productId = productId;
    }
    @ManyToOne(fetch=FetchType.EAGER,optional=false)
    @JoinColumn(name="ORDER_ID",
    referencedColumnName="ORDER_ID",insertable=false,updatable=false,
    nullable=false,unique=true)
    public CustomerOrder getCustomerOrder() {
    return customerOrder;
    }
    public void setCustomerOrder(CustomerOrder customerOrder) {
    this.customerOrder = customerOrder;
    }

    }

    LineItem 类有一个 CustomerOrder 属性。这里定义了一个多对一关系,如上面所示。类似地,LineItem 类与产品对象也具有多对一关系。

    另一映射类型是,表可能有一对一关系,但对象模型只有一个对象。换句话说,您希望在跨多个表映射单一对象(在某种程度上与依赖对象相反)。可以通过添加一个或多个辅助表做到这一点。下面是跨 Customer 和 Order 表映射客户对象的一个示例。

    清单 29

                                
    @Entity
    @Table(name="CUSTOMER")
    @SecondaryTable(name="ORDER ",
    pkJoin=@PrimaryKeyJoinColumn(name="CUST_ID"))
    public class Customer { ... }

  8. 约束:标注和数据库

    JPA 除支持各种数据库约束外,还可以使用它定义对各种关系的约束:

    清单 30

                                
    @OneToMany(mappedBy="customerOrder", cascade=CascadeType.ALL ,
    fetch=FetchType.EAGER)
    public Collection<LineItem> getLineItems() {
    return lineItems;
    }
    public void setLineItems(Collection<LineItem> lineItems) {
    this.lineItems = lineItems;
    }

    在本例中显示了级联影响。例如,如果删除了客户,也将删除客户的顺序。下面是一个具有更多约束的示例:

    清单 31
                                
    @ManyToOne(fetch=FetchType.EAGER,optional=false)
    @JoinColumn(name="CUSTOMER_ID", referencedColumnName="CUST_ID",
    insertable=false,updatable=false, nullable=false,unique=true)

    public Customer getCustomer() {
    return customer;
    }
    public void setCustomer(Customer customer) {
    this.customer = customer;
    }

    在上例中,跨外键(也是主键的一部分)定义了多对一关系。在本例中,不允许任何人更新或插入同样标记为唯一和不得为空的列。此关系也指定为不可选。JPA 还可让您在特定实体上定义唯一约束,如下所示:

    清单 32
                                
    @Entity
    @Table(
    name="EMPLOYEE",
    uniqueConstraints=
    {@UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"})}
    )

  9. 继承:标注——单个表、联合表和按类表

    JPA 规范定义了对映射继承的三种类型的支持;其中只有一种在当前规范中是强制的:

    • 单个表:对象树映射到一个表。
    • 联合表:(可选)将子类映射到与父类映射到的表具有外键关系的表。
    • 按类表:(可选)每个具体的子类映射到一个表,并且包含超类属性的列。

    下面是一个使用单表策略映射超类和子类的示例:

    清单 33

                                
    @Entity
    @Table(name="CUST")
    @Inheritance(strategy=SINGLE_TABLE,
    discriminatorType=STRING,

    discriminatorValue="CUST")
    public class Customer { ... }


    @Entity
    @Inheritance(discriminatorValue="VCUST")
    public class ValuedCustomer extends Customer { ... }

    下面是一个使用联合表策略的示例:

    清单 34
                                
    @Entity
    @Table(name="CUST")
    @Inheritance(strategy=JOINED,
    discriminatorType=STRING,
    discriminatorValue="CUST")
    public class Customer { ... }

    @Entity
    @Table(name="VCUST")
    @Inheritance(discriminatorValue="VCUST")
    @PrimaryKeyJoinColumn(name="CUST_ID")
    public class ValuedCustomer extends Customer { ... }

请参阅参考资料,以了解 JPA 中提供的更多其他功能。





回页首


JAX-WS

Java EE 5 还为 Web 服务引入了一个新的编程模型:JAX-WS。在了解不同之处之前,您需要知道从 JAX-RPC 到 JAX-WS 哪些内容没有发生变化:

  • JAX-WS 仍然支持 SOAP 1.1 over HTTP 1.1,因此互操作性将不会受到影响。仍然可以在网上传递相同的消息。
  • JAX-WS 仍然支持 WSDL 1.1,因此您所学到的有关该规范的知识仍然有用。新的 WSDL 2.0 规范已经接近完成,但在 JAX-WS 2.0 相关工作结束时其工作仍在进行中。

系列文章 Web 服务提示与技巧:JAX-RPC 与 JAX-WS 的比较包含关于 JAX-WS 的详细信息,下面大致列出了从 JAX-RPC 1.1 到 JAX-WS 2.0 都发生了哪些更改:

  • SOAP 1.2:JAX-RPC 和 JAX-WS 都支持 SOAP 1.1。JAX-WS 还支持 SOAP 1.2。
  • XML/HTTP:WSDL 1.1 规范在 HTTP 绑定中定义,这意味着利用此规范可以在不使用 SOAP 的情况下通过 HTTP 发送 XML 消息。JAX-RPC 忽略了 HTTP 绑定。而 JAX-WS 添加了对其的支持。
  • WS-I Basic Profile:JAX-RPC 支持 WS-I Basic Profile (BP) V1.0。JAX-WS 支持 BP 1.1。(WS-I 即 Web 服务互操作性组织。)
  • 新的 Java 功能:JAX-RPC 映射到 Java 1.4。JAX-WS 映射到 Java 5.0。JAX-WS 依赖于 Java 5.0 中的很多新功能。(Java EE 5 是 J2EE 1.4 的后续版本,添加了对 JAX-WS 的支持,但仍然支持 JAX-RPC,这可能会对 Web 服务新手造成混淆。)
  • 数据映射模型:JAX-RPC 具有自己的映射模型,此模型大约涵盖了所有模式类型中的 90%。那些没有包括的模式被映射到 javax.xml.soap.SOAPElement(JAX-WS 数据映射模型是 JAXB,该模型映射所有 XML 模式)。
  • 接口映射模型:JAX-WS 的基本接口映射模型与 JAX-RPC 的区别并不大,不过 JAX-WS 模型使用新的 Java 5.0 功能,并引入了异步功能。
  • 动态编程模型:JAX-WS 的动态客户端模式与 JAX-RPC 模式差别很大。根据业界的需要进行了许多更改,其中包括面向消息的功能和动态异步功能。JAX-WS 还添加了动态服务器模型,而 JAX-RPC 则没有此模型。
  • 消息传输优化机制 (MTOM):JAX-WS 通过 JAXB 添加了对新附件规范 MTOM 的支持,因此应该能够实现附件互操作性。
  • 处理程序模型:从 JAX-RPC 到 JAX-WS 的过程中,处理程序模型发生了很大的变化。JAX-RPC 处理程序依赖于 SAAJ 1.2,而 JAX-WS 处理程序则依赖于新的 SAAJ 1.3 规范。

JAX-WS 还可以与 EJB 3.0 一起使用来简化编程模型。例如,下面的代码显示了将 EJB 3.0 POJO 转换为 Web 服务的简单方法:


清单 35
                
@WebService public interface StockQuote {
public float getQuote(String sym);
}

@Stateless public class QuoteBean implements StockQuote {
public float getQuote(String sym) { ... }
}

还添加了其他标注以便支持 Web 服务中更高级的功能。JAX-B 提供了 POJO(清单 36)和 XML 模式(清单 37)之间的标准映射,下面给出了它的一个示例:


清单 36
                
@XmlType
public class Trade {
@XmlElement(name="tickerSymbol")
public String symbol;
@XmlAttribute
int getQuantity() {...}
void setQuantity() {...}
}


清单 37
                
<xs:complexType name="trade">
<xs:sequence>
<xs:element
name="tickerSymbol"
type="xs:string"/>
</xs:sequence>
<xs:attribute name="quantity"
type="xs:int"/>
</xs:complexType>





回页首


JavaServer Faces

JavaServer™ Faces (JSF) 到目前为止已有数年的历史,并且受大多数 Java EE 应用服务器支持,例如 IBM® WebSphere Application Server。在 Java EE 5 中,JSF 现在是 Java EE 5 规范的一部分。JSF 为 Java EE 应用程序提供了许多好处:

  • 丰富、可扩展的 UI 组件。
  • 事件驱动。
  • 托管组件状态。
  • 呈现器/客户端独立性。
  • 验证程序。
  • 类型转换。
  • 外部化导航。
  • JavaServer Pages 和 Faces 通用表达语言。




回页首


展望 Java EE 6

最近对 JSR 316 (Java EE 6) 提出了一些议案,尽管对其规范定义为时尚早,但该议案突出了以下几个重要主题:

  • 可扩展性:通过添加更多扩展点和更多服务提供程序接口,可以将其他技术简洁高效地插入平台实现,从而实现了可增长性。

  • 概要:概 要将根据 JCP 过程的定义参考 Java EE 平台,并且可能包括 Java EE 平台技术的子集或/和不属于基本 Java EE 平台的其他 JCP 技术。专家组还将定义 Java EE Web 概要的第一个版本,这是一个用于 Web 应用程序开发的 Java EE 平台的子集。

  • 技术修剪:Java EE 平台中的一些技术不再具有它们刚引入平台时的相关性。需要有一种方法,能够认真有序地将这些技术从平台中“修剪”掉,并让仍使用这些技术的开发人员受到的 影响降到最小,同时使平台能够更健壮地成长。正如该过程定义的那样,专家组将考虑在将来的 Java EE 平台规范中应将某些技术标记为可被移除。这些可能被移除的技术包括:

    • EJB CMP,被 Java Persistence 有效地代替。
    • JAX-RPC,被 JAX-WS 有效地代替。
  • SOA 支持:Java EE 平台已经广泛应用于 SOA 应用程序。随着越来越多的企业认识到 SOA 体系结构的好处,对该平台的功能和互操作性的需要也相应提高。Java EE 6 需要考虑增加对 Web 服务的支持。尽管基本 Web 服务支持现在是 Java SE 6 平台的一部分,但此规范将需要这些技术的更新版本,以便提供更多的 Web 服务支持。服务组件体系结构 (SCA) 定义一些可以在 SOA 环境中由组合应用程序使用的工具。专家组在考虑将所有 SCA 定义的工具都包含在 Java EE 6 平台中是否合适。

  • 其他增加内容:专家组提议在 Java EE 6 中包括下列新的 JSR:

    • 用于容器的 JSR-196 Java 身份验证 SPI。
    • 用于应用服务器的 JSR-236 计时器。
    • 用于应用服务器的 JSR-237 工作管理器。
    • JSR-299 Web Bean。
    • JSR-311 JAX-RS:用于 RESTful Web 服务的 Java API。

预计在以下领域进行进一步更新:

  • Enterprise JavaBeans。
  • Java Persistence API。
  • Servlet。
  • JavaServer Faces。
  • JAX-WS。
  • Java EE Connector API。

具体要包括哪些技术将由专家组根据合作伙伴和客户要求确定。其中一些规范还要考虑快速发展的 Web 2.0 空间。





回页首


结束语

Java EE 5 是一个功能强大而重要的发行版,是用于企业开发的最完善的版本。显然,已经采取了一些重要步骤解决了围绕以前 Java 开发的一些问题。EJB 3.0 和 JPA 是功能强大而又易用的技术,而且 JAX-WS 中的增强功能使得 Web 服务的开发比以往更加容易。





回页首


致谢

作者感谢 Jim Knutson 和 Russell Butek 对本文所做的贡献。



参考资料

学习

获得产品和技术


关于作者

Roland Barcia 的照片

Roland Barcia 是位于纽约/新泽西州 Metro 区 IBM WebSphere 软件服务部 的 IT 咨询专家。他是 IBM WebSphere: Deployment and Advanced Configuration 的合著者。有关 Roland 的详细信息,请访问他的网站

 

posted on 2008-01-29 21:16  岚之山  阅读(231)  评论(0编辑  收藏  举报

导航