软件构件与中间件技术 - EJB续

课程信息

  • 讲师: 林慧苹
  • 机构: 北京大学软件与微电子学院
  • 联系方式: linhp@ss.pku.edu.cn

课程大纲

  1. 会话构件
  2. 实体构件
  3. 消息驱动构件

EJB 构件分类

会话构件

  • 有态会话构件: BMP (Bean-Managed Persistence)
  • 无态会话构件: CMP (Container-Managed Persistence)

实体构件

  • 特征:
    • 持久性
    • 可以同时为多个客户服务
    • 生命周期较长
    • 当 EJB 容器崩溃时,可以被恢复

消息驱动构件

  • 特征:
    • 为单个客户发出的消息服务
    • 不直接表示数据库中的共享数据
    • 生命周期相对较短
    • 无状态

EJB 3.0

  • 简化:
    • 减少了在创建 EJB 时所需的类、接口、部署描述符的数量
    • 使用纯旧式 Java 对象(POJO)和纯旧式 Java 接口(POJI)

实例代码

有状态会话 Bean 实例: HotelClerk bean

import javax.ejb.SessionBean;
import javax.naming.InitialContext;
 
public class HotelClerkBean implements SessionBean {
    InitialContext jndiContext;
    //conversational-state
    Customer cust;
    Vector resVector = new Vector();
 
    public void ejbCreate(Customer customer) {
        cust = customer;
    }
 
    public void addReservation(Name name, RoomInfo ri, Date from, Date to) {
        ReservationInfo resInfo = new ReservationInfo(name, ri, from, to);
        resVector.addElement(resInfo);
    }
 
    public void reserveRooms() {
        CreditCard card = cust.getCreditCard();
        Enumeration resEnum = resVector.elements();
        while (resEnum.hasMoreElements()) {
            ReservationInfo resInfo = (ReservationInfo) resEnum.nextElement();
            RoomHome roomHome = (RoomHome) getHome("java:comp/env/ejb/RoomEJB", RoomHome.class);
            Room room = roomHome.findByPrimaryKey(resInfo.roomInfo.getID());
            double amount = room.getPrice(resInfo.from, resInfo.to);
            CreditServiceHome creditHome = (CreditServiceHome) getHome("java:comp/env/ejb/CreditServiceEJB", CreditServiceHome.class);
            CreditService creditAgent = creditHome.create();
            creditAgent.verify(card, amount);
            ReservationHome resHome = (ReservationHome) getHome("java:comp/env/ejb/ReservationEJB", ReservationHome.class);
            Reservation reservation = resHome.create(resInfo.getName(), resInfo.roomInfo, resInfo.from, resInfo.to);
        }
    }
 
    public RoomInfo[] availableRooms(Location loc, Date from, Date to) {
        // Make an SQL call to find available rooms
    }
 
    private Object getHome(String path, Class type) {
        Object ref = jndiContext.lookup(path);
        return PortableRemoteObject.narrow(ref, type);
    }
}

无状态会话 Bean 实例: CreditService bean

import javax.ejb.SessionBean;
 
public class CreditServiceBean implements SessionBean {
    URL acmeURL;
    HttpURLConnection acmeCon;
 
    public void ejbCreate() {
        try {
            InitialContext jndiContext = new InitialContext();
            acmeURL = (URL) jndiContext.lookup("java:comp/ejb/env/url/acme");
            acmeCon = acmeURL.openConnection();
        } catch (Exception e) {
            throw new EJBException(e);
        }
    }
 
    public void verify(CreditCard card, double amount) {
        String response = post("verify:" + card.postString() + ":" + amount);
        if (response.substring("approved") == -1)
            throw new CreditServiceException("denied");
    }
 
    public void charge(CreditCard card, double amount) throws CreditServiceException {
        String response = post("charge:" + card.postString() + ":" + amount);
        if (response.substring("approved") == -1)
            throw new CreditServiceException("denied");
    }
 
    private String post(String request) {
        try {
            acmeCon.connect();
            acmeCon.setRequestMethod("POST " + request);
            String response = acmeCon.getResponseMessage();
        } catch (IOException ioe) {
            throw new EJBException(ioe);
        }
    }
 
    public void ejbRemove() {
        acmeCon.disconnect();
    }
 
    public void setSessionContext(SessionContext cntx) {}
    public void ejbActivate() {}
    public void ejbPassivate() {}
}

EJB 3.0 实例

package com.foshanshop.ejb3;
 
public interface HelloWorld {
    public String SayHello(String name);
}
 
package com.foshanshop.ejb3.impl;
import com.foshanshop.ejb3.HelloWorld;
import javax.ejb.Remote;
import javax.ejb.Stateless;
 
@Stateless
@Remote({HelloWorld.class})
public class HelloWorldBean implements HelloWorld {
    public String SayHello(String name) {
        return name + "说:你好!!";
    }
}

实体 Bean 实例

import javax.ejb.EntityBean;
 
public class CustomerBean implements EntityBean {
    int customerID;
    Address myAddress;
    Name myName;
    CreditCard myCreditCard;
 
    // CREATION METHODS
    public Integer ejbCreate(Integer id) {
        customerID = id.intValue();
        return null;
    }
 
    public void ejbPostCreate(Integer id) {}
 
    public Customer ejbCreate(Integer id, Name name) {
        myName = name;
        return ejbCreate(id);
    }
 
    public void ejbPostCreate(Integer id, Name name) {}
 
    // BUSINESS METHODS
    public Name getName() {
        return myName;
    }
 
    public void setName(Name name) {
        myName = name;
    }
 
    public Address getAddress() {
        return myAddress;
    }
 
    public void setAddress(Address address) {
        myAddress = address;
    }
 
    public CreditCard getCreditCard() {
        return myCreditCard;
    }
 
    public void setCreditCard(CreditCard card) {
        myCreditCard = card;
    }
 
    // CALLBACK METHODS
    public void setEntityContext(EntityContext cntx) {}
 
    public void unsetEntityContext() {}
 
    public void ejbLoad() {}
 
    public void ejbStore() {}
 
    public void ejbActivate() {}
 
    public void ejbPassivate() {}
 
    public void ejbRemove() {}
}

Customer Bean 从属对象定义

// The Name class
public class Name implements Serializable {
    public String lastName, firstName, middleName;
 
    public Name(String lastName, String firstName, String middleName) {
        this.lastName = lastName;
        this.firstName = firstName;
        this.middleName = middleName;
    }
 
    public Name() {}
}
 
// The Address class
public class Address implements Serializable {
    public String street, city, state, zip;
 
    public Address(String street, String city, String state, String zip) {
        this.street = street;
        this.city = city;
        this.state = state;
        this.zip = zip;
    }
 
    public Address() {}
}
 
// The CreditCard class
public class CreditCard implements Serializable {
    public String number, type, name;
    public Date expDate;
 
    public CreditCard(String number, String type, String name, Date expDate) {
        this.number = number;
        this.type = type;
        this.name = name;
        this.expDate = expDate;
    }
 
    public CreditCard() {}
}

CustomerBean 到数据库表的映射

CREATE TABLE CUSTOMER {
    id INTEGER PRIMARY KEY,
    last_name CHAR(30),
    first_name CHAR(20),
    middle_name CHAR(20),
    street CHAR(50),
    city CHAR(20),
    state CHAR(2),
    zip CHAR(9),
    credit_number CHAR(20),
    credit_date DATE,
    credit_name CHAR(20),
    credit_type CHAR(10)
}

远程接口实例: Customer bean 的远程接口定义

import javax.ejb.EJBObject;
 
public interface Customer extends EJBObject {
    public Name getName() throws RemoteException;
    public void setName(Name name) throws RemoteException;
    public Address getAddress() throws RemoteException;
    public void setAddress(Address address) throws RemoteException;
    public CreditCard getCreditCard() throws RemoteException;
    public void setCreditCard(CreditCard card) throws RemoteException;
}

EJB 与 IIOP

  • 互操作: 通过 IIOP 调用 home 接口与 remote 接口
  • 事务传播: 通过 IIOP 传播事务上下文
  • 安全传播: 通过 IIOP 传播安全上下文
  • 命名空间: 通过 IIOP 组织命名空间

COM 与 EJB 的比较

共性

  1. 基本形态相同
  2. 可以独立封装并可以动态加载
  3. 在运行过程中支持接口
  4. 都对构件进行生命周期管理
  5. 构件的运行环境包括众多的公共服务

区别

  1. 基础不同: EJB 规范吸收的是现有技术的解决方法,基本上不考虑对现有技术实现的兼容
  2. 支持环境的实现不同: EJB 的支持环境运行于操作系统之上,体现了一种大粒度的模块化思想
  3. 支持的语言不同: EJB 仅支持 Java 语言,COM 支持 C、C++、Basic 等
  4. 构件交互模式不同: 交互的协议、合约、标识方式皆不同
  5. 构件生命周期的实现方式不同: EJB 主要通过容器实现,独立于具体的构件实现;COM 主要通过类厂实现,与具体的构件实现一一对应

思考题

  1. EJB 构件包含哪些接口?
  2. EJB 构件是如何封装的?
  3. EJB 构件是如何分类的?
  4. COM 与 EJB 有什么异同?