EJB学习一

一、一个企业级Bean是由几个文件共同组成:
1、Bean类
SessionBean实现javax.ejb.SessionBean接口;
EntityBean实现javax.ejb.EntityBean接口。

2、EJB接口(远程接口或者本地接口)和EJB对象
远程接口继承javax.ejb.EJBObject接口;
本地接口继承javax.ejb.EJBLocalObject接口。

3、Home接口(远程接口或者本地接口)和Home对象
远程接口继承javax.ejb.EJBHome接口;
本地接口继承javax.ejb.EJBLocalHome接口。

4、部署描述文件

5、供应商特有文件

二、企业级Bean的调用:
Bean的客户端不直接调用Bean类实例本身,而是通过EJB对象来调用。所以EJB对象必须知道Bean类公开的每个商务方法。
EJB对象就是实现了EJB接口的对象,由容器或容器供应商提供的工具自动生成。

三、客户端如何获得EJB对象的引用:
EJB对象的引用通过Home对象来得到。Home对象就是实现了Home接口的对象,也是由EJB容器自动生成。

四、部署描述文件
在部署描述文件中声明对中间件服务的要求,EJB容器检查部署描述符,并完成要求:
1、Bean的管理和生命周期
2、持久性要求(仅限实体Bean)
3、事务处理要求
4、安全性要求
部署描述文件是一个xml文件。

五、供应商特有文件
每个EJB服务器供应商都不尽相同,他们各自都有一些独特的增值特性。
举例:
<jboss>
    <enterprise-beans>
        <session>
            <ejb-name>Hello</ejb-name>
            <jndi-name>Hello</jndi-name>
            <local-jndi-name>HelloLocal</local-jndi-name>
        </session>
    </enterprise-beans>
</jboss>

六、客户端调用EJB的步骤:
1、通过JNDI查找EJB对象的位置;
2、调用Home对象的create()方法创建EJB对象;
3、调用EJB对象的商务方法;
4、调用EJB对象的remove()方法。

说明:客户端调用EJB一般使用远程调用,因为WEB服务器和EJB服务器可能位于两台机器;
      EJB调用EJB一般使用本地调用,因为它们通常都位于同一个EJB容器内。

七、客户端调用EJB代码举例:
1、远程调用例子:
public class HelloTestClient1 extends Object {
  public static void main(String[] args) {

    HelloHome helloHome = null;
    Hello hello = null;
    java.util.Hashtable JNDIParm = new java.util.Hashtable();
    JNDIParm.put(Context.PROVIDER_URL, "localhost");
    JNDIParm.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");
    try {
      javax.naming.Context ctx = new InitialContext(JNDIParm);
     
      Object ref = ctx.lookup("Hello");

      //创建Home对象
      helloHome = (HelloHome) PortableRemoteObject.narrow(ref, HelloHome.class);
      //创建EJB对象
      hello = helloHome.create();
      //调用EJB对象的商务方法
      System.out.println(hello.hello());
      //EJB对象使用完毕后,要从内存中将它清除
      hello.remove();
    }
    catch (Exception ex) {
      System.out.println(ex);
    }
  }
}

2、本地调用例子:
      //通过调用无参数的构造函数,获得默认的初始化上下文
      javax.naming.Context ctx = new InitialContext();

      Object ref = ctx.lookup("java:comp/env/ejb/LocalUser");
      //创建Home对象
      localUserHome = (LocalUserHome) PortableRemoteObject.narrow(ref, LocalUserHome.class);
      //创建EJB对象
      localUser = localUserHome.create();
      System.out.println(localUser.hello());
      //EJB使用完毕后,要从内存中将它清除
      localUser.remove();
   .
   .
   .
说明:本地调用必须将下面的内容添加到ejb-jar.xml的部署描述符的 session 元素中,如下所示: 
<session>

      ...
      <ejb-local-ref>
        <ejb-ref-name>ejb/LocalUser</ejb-ref-name>
        <ejb-ref-type>Entity</ejb-ref-type>
        <local-home>com.rickhightower.auth.LocalUserHome</local-home>
        <local>com.rickhightower.auth.LocalUser</local>
        <ejb-link>userEntity.jar#UserBean</ejb-link>
      </ejb-local-ref>
   ...  
请注意 ejb-local-ref 定义了对 UserBean 的引用。
   
八、有状态的session bean
1、一个有状态的session bean始终和一个客户相联系,在众多的方法调用过程中,这个实例代表的客户都保持一定的状态。
有状态的session bean类的实例总是同一个对象联系在一起,并同该对象绑定在一起用来指明一个确切的客户。
虽然web应用定义了http会话的概念,可以将一个业务的处理流程直接嵌入web应用的实现中,但是将业务处理封装在一个会话bean中将更加合适。

2、有状态的session bean的“激活”和“钝化”
容器如果按照有状态会话Bean的设想来实现的话。那么有限的资源如:内存、数据库连接等就会被耗费很多。
容器使用“激活”和“钝化”的方法来解决这一矛盾。

九、实体EJB
1、实体Bean是能够存放在永久性存储空间中的持久对象。这样我们就可以使用实体Bean来对商务中的数据进行建模。

2、一个实体Bean类可以映射一个关系型表的定义。这个类的一个实体将会映射那个表中的一行。实体Bean类提供一些访问数据和操作数据的简单方法。

3、实体Bean的主键类
EJB通过让实体Bean包含一个主键类,提供了定义您的唯一标识的灵活性。主键对象的属性没有必要和持久化主键数据完全一致。
主键类必须是可以序列化的(实现java.io.Serializable接口)。

4、并发访问问题
EJB规定只有一个线程可以不断的运行在一个Bean实例当中。会话Bean、实体Bean都是单线程的。
对于多客户端访问同一数据,容器实例化同一个实体Bean类的多个实例,每个实例都代表同一个底层实体数据。
容器根据事务来在适当的时候调用ejbLoad()和ejbStore()方法。同步数据。
从客户端的角度,它认为它在处理单个的实体Bean的实例。

十、从连接池获得JDBC连接
public Connection getConnection() throws Exception {
    try {

      Context ctx = new InitialContext();
      DataSource ds = (DataSource) ctx.lookup("java:/MySQLDB");
      return ds.getConnection();
    }
    catch (Exception e) {
      System.out.println("没有取得数据源");
      e.printStackTrace();
      throw e;
    }
}

十一、容器管理的持久实体Bean(CMP)
1、用容器管理的持久化,不用再在实体Bean自身中实现任何持久逻辑(如,JDBC/SQL),而是由容器为您执行存储空间的操作。

2、数据库无关的Bean
如果我们要开发一个可重用的组件,我们很可能不知道Bean的使用者将要使用什么样的数据库存储。在CMP中,实体Bean和它的持久化表现完全分开。

3、容器的作用
不能在CMP实体Bean中编写任何JDBC和其他持久化逻辑。容器通过继承实体Bean类来生成JDBC代码。

4、所有的CMP实体Bean类被分解为两个类:一个类是超类,这个类需要自己编写,它包含实体Bean的数据逻辑。
另外一个是子类,这个类由容器生成,它包含持久化逻辑。所以实际的CMP实体Bean类是一个超类和一个子类的组合。

十二、EJB-QL
1、EJB-QL是一种语法类似于SQL、面向对象、用于查询实体Bean的查询语言。
举例:
SELECT OBJECT(a) FROM Product AS a WHERE a.name = ?

十三、开发一个CMP的步骤
1、构建CMP实体Bean类

2、设计抽象持久化模型(关于持久化的部署描述,称为“抽象持久化模式”)

3、编写EJB-QL

十四、实体Bean 的增、删、改、查
1、新增
如下所示:
LocalUser user = userHome.create(email, password);
提示:我们并没有在 home 接口中定义新增方法,该方法是从 javax.ejb.EJBLocalHome 接口继承的,由 EJB 容器实现。

2、删除
如下所示:
userHome.remove(email);
由于电子邮件地址是主键,因此它可以用来唯一地标识实体,用 home 接口的删除方法来删除它。
提示:我们并没有在 home 接口中定义删除方法,该方法是从 javax.ejb.EJBLocalHome 接口继承的,由 EJB 容器实现。

3、修改
如下所示:
LocalUser user = userHome.findByPrimaryKey(email);
user.setName("SWANGOOSE");
使用 LocalUserHome 的 findByPrimaryKey() 方法来查找与 email 主键相关联的 UserBean 实例,然后修改。

4、查询
有了 EJB 2.0 CMP,您只需使用 EJB-QL 在部署描述符中定义查找程序方法的定义。
您仍然还必须在 home 接口中声明这个查找程序方法。
请注意查找程序方法 public Collection findAll() throws FinderException 是在 home 中声明的。
举例如下:
public interface LocalUserHome extends EJBLocalHome
{
    public Collection findAll() throws FinderException;
}
    
      
   
    <entity>
      <display-name>UserBean</display-name>
      <ejb-name>UserBean</ejb-name>

      <query>
        <description></description>
        <query-method>
          <method-name>findAll</method-name>
          <method-params />
        </query-method>
        <ejb-ql>
         <![CDATA[select Object(theUser) from UserBean as theUser]]>
        </ejb-ql>
      </query>

    </entity>


十五、使用简单的EJB-QL命令
1、简单查询许多实体
例如:为了返回系统中所有的 Group,您要使用下列 EJB-QL:
SELECT OBJECT(g) FROM UserGroup g
您将模式名用于 abstract-schema-name 元素定义的实体 bean,而不是用 FROM 子句中的表或视图。

为了定义 findAll() 方法,您要做以下的工作:
1、1 在 home 接口中定义一个 findAll() 方法;
1、2 为查找程序定义包含 EJB-QL 的查询元素。

返回多个实体的 findAll() 查找程序方法看上去就像这样:
public Collection findAll()  throws javax.ejb.FinderException;

请注意,返回多个实体的查找程序方法必须返回 java.util.Collection 或 java.util.Set。
(确保返回 java.util.Set 的查找程序方法在 Set 中仅返回一次实体。)还要注意,必须声明所有的查找程序方法都抛出 javax.ejb.FinderException。

query 元素由 query-method、result-type-mapping 和 ejb-ql 元素组成,如下所示:

          <query>
             <query-method>
                <method-name>findAll</method-name>
                <method-params>
                </method-params>
             </query-method>
             <result-type-mapping>Local</result-type-mapping>
             <ejb-ql><![CDATA[
                     SELECT OBJECT(g) FROM UserGroup g
             ]]></ejb-ql>
          </query>

result-type-mapping 元素指出查找程序方法返回的是实体 bean 的本地接口还是远程接口。在这个例子中,您将返回本地接口。
ejb-ql 元素是定义用于查询的 EJB-QL 的地方。
请注意,FROM 子句使用 Group 实体 bean 的模式名 UserGroup。还要注意 OBJECT 关键字的使用,它必须用于返回实体 bean。上面的查询返回系统中所有的 Group。

2、简单查询单独的实体
我们来假设您想创建一个查询,来查找组名等于某一个您感兴趣的名称的组。您要使用下列 EJB-QL:
SELECT OBJECT(g) FROM UserGroup g WHERE g.name = ?1

?1 指的是方法的第一个参数。如果有两个参数,那么 ?2 指的是传递给查找程序方法的第二个参数,依此类推。

上面示例的 home 接口的查找程序方法如下:

    public GroupLocal findByGroupName(String name)
                            throws javax.ejb.FinderException;
请注意,这个查找程序方法还说明了一个查找程序,该查找程序期望用一个单独的实体作为结果,因为它返回 GroupLocal 而不是 Collection。事实上,如果查询返回不止一个结果,将抛出 FinderException。

因为这个方法只用了一个参数,所以必须在部署描述符中用 method-param 元素声明这个参数,如下所示:
          <query>
             <query-method>
                <method-name>findByGroupName</method-name>
                <method-params>
                   <method-param>java.lang.String</method-param>
                </method-params>
             </query-method>
 ...
          </query>


请注意,WHERE 子句(和 g.name 中一样)中使用的 name 是一个 CMP 字段。


SELECT OBJECT(g) FROM UserGroup g WHERE g.name = ?1


因此,CMP 字段可以用在 EJB-QL 查询中。

3、高级 EJB-QL,包括:

比较操作符,包括 LIKE
选择方法
逻辑操作符
BETWEEN 子句
IS NULL

比如:
SELECT DISTINCT OBJECT(user)
FROM User user
WHERE user.group.name IN ('engineering','IT')

(其他,详见资料或书籍)

十六、容器管理的关系(CMR)
1、关系类型,如下所示:
一对一
一对多
多对多

这些关系在 XML 部署描述符中定义。

2、举例说明
有四个截然不同的实体:User、Group、Role 以及 UserInfo。这些实体中的每一个都有下面这三种关系:
多个 User 与多个 Role 相关联(多对多)
一个 User 有一个 UserInfo(一对一)
一个 Group 包含多个 User(一对多)

请注意下面的代码:

public abstract LocalUser getUser();
public abstract void setUser(LocalUser user);

在 UserInfoBean 的本地接口和实现中都有。这个 setter 和 getter 方法定义这个双向关系的 CMR 字段。
因为这个关系是双向的,所以 UserInfo 和 UserInfoBean 都必须有引用对方的 CMR 字段。

3、UserInfoBean 的部署描述符
请注意,一个关系中所涉及的实体必须在同一个部署描述符中定义;这样,必须在同一个 .jar 文件中打包这些实体。
UserBean 和 UserInfoBean 一起在同一个 EJB .jar 文件中打包,并且一起在同一个部署描述符中定义。

4、在部署描述符中定义一对一关系:
关系在 <enterprise-beans> 元素之外定义。当您指定关系时,您必须指定关系中所涉及的两个实体 bean。
关系在 <ejb-relation> 元素中定义。关系中的每个角色在 <ejb-relationship-role> 元素中定义。

比如:
  <relationships>
    <ejb-relation>
      <ejb-relation-name>UserHasUserInfo</ejb-relation-name>

      <ejb-relationship-role>
        <ejb-relationship-role-name>
    UserHasUserInfo
        </ejb-relationship-role-name>
   
        <multiplicity>One</multiplicity>
        <relationship-role-source>
          <ejb-name>UserBean</ejb-name>
        </relationship-role-source>
        <cmr-field>
          <cmr-field-name>userInfo</cmr-field-name>
        </cmr-field>
      </ejb-relationship-role>

      <ejb-relationship-role>
        <ejb-relationship-role-name>
    UserInfoPartOfUser
        </ejb-relationship-role-name>
   
        <multiplicity>One</multiplicity>
        <cascade-delete />
        <relationship-role-source>
          <ejb-name>UserInfoBean</ejb-name>
        </relationship-role-source>
        <cmr-field>
          <cmr-field-name>user</cmr-field-name>
        </cmr-field>
      </ejb-relationship-role>

    </ejb-relation>
  </relationships>

<ejb-relationship-role> 有名称、多样性、源以及可选的 CMR 字段,分别由下面这些元素定义:
分别是 <ejb-relationship-role-name>、<multiplicity>、带有 <ejb-name> 子元素的 <relationship-role-source>
以及带有 <cmr-field-name> 子元素的 <cmr-field>。

现在说明一下:
<ejb-relationship-role-name> 元素体可以是您所希望的任何名称。请尽量使它对于您所描述的关系具有描述性。
另外,请尽量使它在部署描述符的上下文中是唯一的。

<relationship-role-source>/<ejb-name> 体必须设置为由 <enterprise-beans> 元素中的实体 /<ejb-name> 定义的 ejb-bean 名。

<cmr-field>/<cmr-field-name> 体必须设置为这一屏中定义的 CMR 字段名。
如果 <cmr-field> 由本地接口中的getUserInfo()和setUserInfo()定义,那么它将由 <cmr-field-name> 中的 userInfo 定义,如下所示:
   
        <cmr-field>
          <cmr-field-name>userInfo</cmr-field-name>
        </cmr-field>
      </ejb-relationship-role>

5、多对多关系
多对多关系听起来极其难以实现。实际上,它和一对一关系一样容易实现。EJB 容器替您做了所有最难做的工作。

对于这个示例,您将添加用户可能处于的不同角色。单个用户可能处于多个角色。并且一个角色可以与多个用户相关联。

在部署描述符中定义多对多关系:
添加多对多关系的 XML 元素和技术与添加一对一关系的 XML 元素和技术基本相同。唯一的关键的不同之处是多样性。
RoleBean 的 <ejb-relationship-role> 没有 CMR 字段元素,因为从 UserBean 到 RoleBean 的关系是单向的。
RoleBean 不知道 UserBean。下面列出了 <ejb-relation> 元素:


    <ejb-relation>
      <ejb-relation-name>UserAssociateWithRoles</ejb-relation-name>

      <ejb-relationship-role>
        <ejb-relationship-role-name>UserBeanToRoleBean</ejb-relationship-role-name>
        <multiplicity>Many</multiplicity>
        <relationship-role-source>
          <ejb-name>UserBean</ejb-name>
        </relationship-role-source>
        <cmr-field>
          <cmr-field-name>roles</cmr-field-name>
          <cmr-field-type>java.util.Collection</cmr-field-type>
        </cmr-field>
      </ejb-relationship-role>

      <ejb-relationship-role>
        <ejb-relationship-role-name>RoleBeanToUserBean</ejb-relationship-role-name>
        <multiplicity>Many</multiplicity>
        <relationship-role-source>
          <ejb-name>RoleBean</ejb-name>
        </relationship-role-source>
      </ejb-relationship-role>

    </ejb-relation>

请注意,UserBeanToRoleBean 的 <multiplicity> 为 Many,而且 UserBeanToRoleBean 的 <cmr-field> 有一个子元素 <cmr-field-type>。<cmr-field-type> 元素用值为 Many 的 <multiplicity> 的关系定义了 Java 代码类型。
请注意,两种可能是 java.util.Collection 和 java.util.Set。因为您选择了 java.util.Collection 以及 CMR 字段名是 roles,那么您可以料到会在返回和设置 java.util.Collection 的 UserBean 的本地接口中看到一个叫做 roles 的 CMR 字段(setter 和 getter 方法对)。

6、一对多关系
和第一个关系示例中的 UserInfoBean 一样,GroupBean 有一个引用 UserBean 的 <cmr-field>。和 UserInfoBean 不同,GroupBean 中的 <cmr-field> 的用户是 UserBean 的集合。

在部署描述符中定义一对多关系:
用来添加一对多关系的 xml 元素和技术与添加一对一和多对多关系的 xml 元素和技术几乎相同。唯一的关键的不同之处是多样性。
GroupBean 的 <ejb-relationship-role> 有一个 CMR 字段元素,因为从 UserBean 到 GroupBean 的关系是双向的。
GroupBean 有一个名为 users 的 CMR 字段。UserBean 有一个名为 group 的 CMR 字段。下面列出了 <ejb-relation> 元素:

    <ejb-relation>

      <ejb-relation-name>GroupsHaveUsers</ejb-relation-name>

      <ejb-relationship-role>
        <ejb-relationship-role-name>GroupHasUsers</ejb-relationship-role-name>
        <multiplicity>One</multiplicity>

        <relationship-role-source>
          <ejb-name>GroupBean</ejb-name>
        </relationship-role-source>

        <cmr-field>
          <cmr-field-name>users</cmr-field-name>
          <cmr-field-type>java.util.Collection</cmr-field-type>
        </cmr-field>

      </ejb-relationship-role>

      <ejb-relationship-role>

        <ejb-relationship-role-name>UsersInGroup</ejb-relationship-role-name>
        <multiplicity>Many</multiplicity>

        <relationship-role-source>
          <ejb-name>UserBean</ejb-name>
        </relationship-role-source>

        <cmr-field>
          <cmr-field-name>group</cmr-field-name>
        </cmr-field>


      </ejb-relationship-role>

    </ejb-relation>

请注意,GroupHasUsers 的 multiplicity 为 One,因为在这个关系中有一个组,并且和上一个示例 GroupHasUsers 的 <cmr-field> 一样,有一个子元素 <cmr-field-type>,如下所示:

        <cmr-field>
          <cmr-field-name>users</cmr-field-name>
          <cmr-field-type>java.util.Collection</cmr-field-type>
        </cmr-field>

字段关系的类型是 java.util.Collection,CMR 字段名是 users。

关系的另一方 UsersInGroup 的 <multiplicity> 为 Many,因为这个组里有很多用户。另请注意将 <cmr-field> 设置为 group。

 

 

你可能感兴趣的:(多线程,bean,ejb,企业应用,电子商务)