Jpa 如何将我的DAOBean从EJB更改为纯CDI?

Jpa 如何将我的DAOBean从EJB更改为纯CDI?,jpa,jakarta-ee,cdi,Jpa,Jakarta Ee,Cdi,我想在新项目中重用AbstractDAO,但这次我不想使用EJB注释-只使用CDI注释 到目前为止,我一直这样使用它: public abstract class AbstractDAO<T> { @PersistenceContext(unitName = "myUnit") private EntityManager entityManager; private Class<T> entityClass; public Abstr

我想在新项目中重用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
}
公共抽象类AbstractDAO{
@PersistenceContext(unitName=“myUnit”)
私人实体管理者实体管理者;
私有类实体类;
公共抽象DAO(类entityClass){
this.entityClass=entityClass;
}
受保护的EntityManager getEntityManager(){
返回实体管理器;
}
公共作废保存(T实体){
entityManager.persist(实体);
}
公共无效更新(T实体){
entityManager.merge(实体);
}
公共无效删除(T实体){
entityManager.remove(entityManager.merge(entity));
}
公共T findById(对象id){
返回entityManager.find(entityClass,id);
}
公共列表findBy(字符串attrName,对象attrValue){
//在这里输入
}
//[…]更多的搜索方法
}
我为每个实体创建了一个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;
  }
}
@无状态
公共类UserDAO扩展了AbstractDAO{
公共用户dao(){
super(User.class);
}
公共用户findByUsername(字符串用户名){
如果(用户名!=null){
返回super.findOneBy(“username”,username.toLowerCase());
}
返回null;
}
}
现在我想去掉@Stateless注释。但是简单地用@RequestScoped构造函数替换它是行不通的,因为JSR-346的非私有构造函数没有参数


如何将DAO重构为纯CDI?

这里有两个问题:CDIBean默认情况下不支持事务-与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
}
公共类抽象DAO{
私有瞬态类实体类;
@抑制警告(“未选中”)
公开摘要(){
类型generalsupercls=getClass().getGenericSuperclass();
if(类的GeneralSupercls实例){
GeneralSupercls=((类)GeneralSupercls.getGenericSuperclass();
}
ParameteredType ParameteredType=(ParameteredType)泛型;
类型类型=ParameteredType.getActualTypeArguments()[0];
if(类型instanceof Class){
this.entityClass=(类)类型;
}else if(参数化类型的instanceof){
this.entityClass=(类)((ParameterizedType)类型).getRawType();
}
}
@持久上下文
私人实体管理者;
公共T getById(对象id)引发ServiceException{
返回getEm().find(entityClass,id);
}
//其他方法如下
}

作为旁注,您为什么要摆脱EJB?与cdi相比,使用池化slsb可以获得更好的性能,而且它们结合得非常好(每个EJB bean在jee容器中也是一个CDIBean)。

UserDAO
有一个无参数的非私有构造函数。而
@PersistenceContext
将在JEE环境中适用于CDIBean。我没有把问题解决好吗?您是否确实尝试过将
UserDAO
@requestscope
设置为受限?错误是什么?只是好奇-你想通过这样做实现什么?我发现CDI和EJB bean的混合让很多人感到困惑(至少在我的上一个项目中是这样)。另外,我读到了:实际的警告是“类型AbstractDAO(具有无参数的非私有构造函数)不是正常作用域bean UserDAO的合法类型,因为它不能由容器代理[JSR-346§3.15]”您真的需要自己实现DAO吗,为什么不看看像DeltaSpike数据这样的库呢,我发现CDI和EJB bean的混合让很多人感到困惑(至少在我的上一个项目中是这样)。另外,我读到了以下内容:。我不知道那场演出。我将尝试您的解决方案您链接的帖子反对混合业务层和数据层,如果您将DAO层与业务服务分离,情况并非如此。EJB和CDIBean都只是容器管理的组件,可以执行各种角色。在内部,它们非常相似(如果您忽略了远程EJB等遗留的负担),一些服务器甚至以一种通用的方式处理它们。每个问题总是有不止一个好的解决方案:)SLSB~=@poolled&@Transactional CDI。但你是对的,做对你的团队有意义的事情,获得10%的额外性能不值得开发者沮丧。