【问题标题】:How to change my DAO Bean from EJB to pure CDI?如何将我的 DAO Bean 从 EJB 更改为纯 CDI?
【发布时间】:2017-05-30 17:09:59
【问题描述】:

我想在一个新项目中重用我的 AbstractDAO,但这次我不想使用 EJB 注释 - 只是 CDI 注释。

到目前为止,我一直是这样使用它的:

public abstract class AbstractDAO<T> {

    @PersistenceContext(unitName = "myUnit")
    private EntityManager entityManager;

    private Class<T> entityClass;

    public AbstractDAO(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

        protected EntityManager getEntityManager() {
        return entityManager;
    }

    public void save(T entity) {
        entityManager.persist(entity);
    }

    public void update(T entity) {
        entityManager.merge(entity);
    }

    public void remove(T entity) {
        entityManager.remove(entityManager.merge(entity));
    }

    public T findById(Object id) {
        return entityManager.find(entityClass, id);
    }

    public List<T> findBy(String attrName, Object attrValue) {
        // Impl here
    }

    // [...] Many more search methods
}

我一直在为每个实体创建一个 DAO,例如:

@Stateless
public class UserDAO extends AbstractDAO<User> {

  public UserDAO() {
    super(User.class);
  }

  public User findByUsername(String username) {
    if (username != null) {
      return super.findOneBy("username", username.toLowerCase());
    }
    return null;
  }
}

现在我想摆脱@Stateless 注释。但是由于 JSR-346

的 non-private constructor with no parameters 要求,简单地用 @RequestScoped 替换它是行不通的

如何将我的 DAO 重构为纯 CDI 的?

【问题讨论】:

  • UserDAO 有一个无参数、非私有的构造函数。 @PersistenceContext 将适用于 JEE 环境中的 CDI bean。我没有解决问题吗?你真的试过制作UserDAO@RequestScoped吗?错误是什么?
  • 只是好奇 - 你这样做是为了达到什么目的?
  • 我发现 CDI 和 EJB bean 的混合让很多人感到困惑(至少在我的上一个项目中是这样)。另外,我读到这个:theelitegentleman.blogspot.de/2014/04/…
  • 实际的警告是“Type AbstractDAO(带有不带参数的非私有构造函数)不是普通作用域 bean UserDAO 的合法类型,因为它不能被容器代理 [ JSR-346 §3.15]"
  • 你真的需要自己实现 DAO,为什么不看看像 DeltaSpike Data 这样的库,它用所有标准方法实现了 DAO。

标签: jpa jakarta-ee cdi


【解决方案1】:

这里有两个问题:CDI bean 默认情况下不支持事务 - 与 EJB 不同,因此如果您想进行保存/更新,则必须使用 @Transactional 限定符... 其次,您的无参数构造函数:您只需将实体类传递给您的抽象类,即使您也将其指定为通用参数。你可以像这样推断实际的类:

public class AbstractDAO<T> {

  private transient Class<T> entityClass;

  @SuppressWarnings("unchecked")
  public AbstractDAO() {
    Type generSuperCls = getClass().getGenericSuperclass();
    if (generSuperCls instanceof Class) {
      generSuperCls = ((Class<?>) generSuperCls).getGenericSuperclass();
    }
    ParameterizedType parameterizedType = (ParameterizedType) generSuperCls;
    Type type = parameterizedType.getActualTypeArguments()[0];
    if (type instanceof Class) {
      this.entityClass = (Class<T>) type;
    } else if (type instanceof ParameterizedType) {
      this.entityClass = (Class<T>) ((ParameterizedType) type).getRawType();
    }
  }

  @PersistenceContext
  private EntityManager em;

  public T getById(Object id) throws ServiceException {
    return getEm().find(entityClass, id);
  }
// other methods follow
}

作为旁注,您为什么要摆脱 EJB? Benchmarks show 使用池化 slsb 可以获得比 cdi 更好的性能,并且它们可以很好地结合在一起(每个 EJB bean 也是 jee 容器中的 CDI bean)。

【讨论】:

  • 我发现 CDI 和 EJB bean 的混合让很多人感到困惑(至少在我的上一个项目中是这样)。另外,我读到了这个:theelitegentleman.blogspot.de/2014/04/…。我不知道表演。我会试试你的解决方案
  • 您链接的帖子反对混合业务和数据层,如果您将 DAO 层与业务服务分开,情况并非如此。 EJB 和 CDI bean 都只是容器管理的组件,可以执行各种角色。在内部,它们非常相似(如果您忽略远程 ejb 的遗留负担等),一些服务器甚至以通用方式处理它们。每个问题总是有不止一个好的解决方案:)SLSB~=@pooled&@Transactional CDI。但你是对的,做对你的团队有意义的事情,获得​​ 10% 的额外性能不值得开发人员沮丧。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-10
相关资源
最近更新 更多