如何将我的DAO Bean从EJB更改为纯CDI?

时间:2017-05-30 17:10:00

标签: jpa java-ee cdi

我想在一个新项目中重用我的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注释。但是简单地用@RequestScoped替换它将无法工作,因为非私有构造函数没有参数要求 JSR-346

如何将DAO重构为纯CDI?

1 个答案:

答案 0 :(得分:2)

这里有两个问题:CDI bean默认情况下不是事务感知 - 不像EJB,所以如果你想进行保存/更新,你必须使用@Transactional限定符... 第二,你的no-arg构造函数:你只需要将实体类传递给抽象类,即使你也将它指定为泛型参数。您可以推断出这样的实际类:

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)。