我想在一个新项目中重用我的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?
答案 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)。