JavaEE 应用程序结构

JavaEE app structure

我正在使用 JEE7 创建网络应用程序。我的问题是关于我的应用程序的架构。基本上,我有几个实体 classes(业务 class)代表将存储在我的数据库中的内容。例如,我有一个实体 class Book 和一个实体 class Comic.
为了访问数据库,我想创建一个 EJB(有点像 DAO 设计模式)。这是我的问题,我在网上找不到准确的答案。

我是否应该为 Book class 和漫画 class 创建一个 @remote 接口和一个具有所有方法的 @stateless class add/delete/get/update ?

或者我应该创建 2 个 @remote 接口和 2 个 @stateless classes (2 EJB),每个实体一个 class ?

因为让我们想象一下我创建了一个更大的网络应用程序。如果我有 100 个实体 classes,使用第一种方法我将拥有一个巨大的 EJB,但使用第二种方法我将拥有 100 个 EJB 及其接口。我认为第二个更好,但我不确定。你怎么看?

Java EE 应用程序体系结构显然是一个庞大的主题,但常见的方法是创建一个会话 EJB 以向您的客户端公开一般 API 调用,然后使用粗粒度的实体 EJB处理您的持久数据。这些实体 EJB 可以管理许多更细粒度的 Java 对象和映射到您的数据库结构的 类。

这可能是一个不错的起点: https://docs.oracle.com/cd/A87860_01/doc/java.817/a83725/entity1.htm

为什么不只使用 one 无状态 bean 和 one 远程接口?

远程 bean 的一个非常好的特性是,它们可以是通用的,所以基本上至少您只需要一个接口和一个远程 bean(参见 SimpleEntity 及其远程 bean)。

我混合使用一个非常通用的远程 bean DAO 来读取简单的实体,并使用一些特定的 bean 来读取需要更多 CUD 操作逻辑的实体。接下来我只是提取了最小的接口来重现它。

如果我创建一个新的 table 和实体,它可以立即在远程客户端上使用。

实体

/* 
 * Complex entity with enhanced CRUD logic
 */
public class Foo implements Entity { }

/*
 * Simple entity without complex CRUD logic
 */
public class Bar implements SimpleEntity { }

界面

public interface Entity { }
public interface SimpleEntity extends Entity { }

/*
 * Generic entity DAO interface, for remote beans and other datasources
 */
public interface IEntityDAO<T extends Entity>
{ 
    public T get(Class<T> type, long id);
    public T update(T t);
}

/*
 * Generic remote bean interface for a JNDI service locator lookup
 */
public interface EntityDAOBeanRemote<T extends Entity> extends IEntityDAO<T> { }

无状态远程 Bean

/*
 * 'abstract' base class for stateless DAO beans
 */
public class AEntityDAOBean<T extends Entity> implements EntityDAOBeanRemote<T>
{
    public T get(Class<T> type, long id)
    {
        Session session = // obtain current hibernate session
        return id == (T) session.createCriteria(type).add(Restrictions.idEq(id)).uniqueResult();
    }

    public T update(T t, long id)
    {
        Session session = // obtain current hibernate session
        session.update(t);
        return t; // return updated instance
    }
}

/*
 * Generic stateless remote DAO bean implementation
 */
@Stateless(mappedName = "SimpleEntityDAOBean")
@Remote(EntityDAOBeanRemote.class)
public class SimpleEntityDAOBean extends AEntityDAOBean<SimpleEntity> implements EntityDAOBeanRemote<SimpleEntity>
{
    // empty since all methods are from parent class
}

/* 
 * Foo specific remote DAO bean
 */
@Stateless(mappedName = "FooDAOBean")
@Remote(EntityDAOBeanRemote.class)
public class FooDAOBean extends AEntityDAOBean<SimpleEntity> implements EntityDAOBeanRemote<Foo>
{
    @Override
    public Foo update(Foo foo) 
    { 
        // make specific foo things and update
        return foo;
    }
}

客户端

在客户端使用 JNDI,您可以使用 JNDI 服务定位器模式调用 bean,例如:

    EntityDAOBeanRemote<Foo> fooDAOBeanRemote = jndiServiceLocator
        .getEntityDAOBeanRemote(Foo.class);

    EntityDAOBeanRemote<Bar> barDAOBeanRemote = jndiServiceLocator
        .getEntityDAOBeanRemote(Bar.class);

客户端 JSF

使用通用的 JSF 转换器和 DAO 的 GUI 框架的通用扩展(例如 PrimeFaces LazyDataModel),它可以节省大量时间,使新实体在 JSF bean 和 edi 中快速访问table 在 GUI 中。