【问题标题】:Design Generic CRUD Session Bean设计通用 CRUD 会话 Bean
【发布时间】:2011-04-12 20:33:12
【问题描述】:

这个问题已经在这里EJB 3 Session Bean Design for Simple CRUD 被问过一次,我只是想问一些关于这个设计的更深入的问题。我已经尝试在原始帖子中提出问题,但是我没有看到任何回复,所以我决定创建新帖子。所以实现通用 CRUD 会话 bean 的 Pascal 解决方案如下

public interface GenericCrudService {
    public <T> T create(T t);
    public <T> T find(Class<T> type, Object id);
    public <T> void delete(T t);
    public <T> T update(T t);
    public List findWithNamedQuery(String queryName);
    public List findWithNamedQuery(String queryName, int resultLimit);
    public List findWithNamedQuery(String namedQueryName, 
                                   Map<String, Object> parameters);
    public List findWithNamedQuery(String namedQueryName, 
                                   Map<String, Object> parameters,
                                   int resultLimit);
    public <T> List<T> findWithNativeQuery(String sql, Class<T> type);
}

@Stateless
@Remote(GenericCrudService.class)
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class GenericCrudServiceBean implements GenericCrudService {
    @PersistenceContext
    private EntityManager em;

    @Override
    public <T> T create(T t) {
        em.persist(t);
        return t;
    }

    @Override
    public <T> T find(Class<T> type, Object id) {
        return em.find(type, id);
    }

    @Override
    public <T> void delete(T t) {
        t = em.merge(t);
        em.remove(t);
    }

    @Override
    public <T> T update(T t) {
        return em.merge(t);
    }

    @Override
    public List findWithNamedQuery(String queryName) {
        return em.createNamedQuery(queryName).getResultList();
    }

    @Override
    public List findWithNamedQuery(String queryName, int resultLimit) {
        return em.createNamedQuery(queryName).setMaxResults(resultLimit)
                .getResultList();
    }

    @Override
    public List findWithNamedQuery(String namedQueryName,
                                   Map<String, Object> parameters) {
        return findWithNamedQuery(namedQueryName, parameters, 0);          
    }

    @Override
    public List findWithNamedQuery(String namedQueryName,
                                   Map<String, Object> parameters,
                                   int resultLimit) {
        Query query = this.em.createNamedQuery(namedQueryName);
        if(resultLimit > 0) {
            query.setMaxResults(resultLimit);            
        }
        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
            query.setParameter(entry.getKey(), entry.getValue());
        }
        return query.getResultList();
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T>  List<T> findWithNativeQuery(String sql, Class<T> type) {
        return em.createNativeQuery(sql, type).getResultList();
    }
}

问题:

1) 当我尝试在我的托管 bean 中引用这个 EJB bean 时,我必须这样做

@EJB
private GenericCrudService myEJB;

而不是

@EJB
private GenericCrudServiceBean myEJB;

这对我来说没什么意义,因为 GenericCrudService 只是一个接口,GenericCrudServiceBean 是无状态 Bean

当我执行GenericCrudServiceBean 时,我得到了这个异常,

Caused by: javax.naming.NamingException: Lookup failed for 'java:comp/env/com.bridgeye.web.Profile/myEJB' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NamingException: Exception resolving Ejb for 'Remote ejb-ref name=com.bridgeye.web.Profile/myEJB,Remote 3.x interface =com.bridgeye.ejb.GenericCRUDServiceBean,ejb-link=null,lookup=,mappedName=,jndi-name=com.bridgeye.ejb.GenericCRUDServiceBean,refType=Session' .  Actual (possibly internal) Remote JNDI name used for lookup is 'com.bridgeye.ejb.GenericCRUDServiceBean#com.bridgeye.ejb.GenericCRUDServiceBean' [Root exception is javax.naming.NamingException: Lookup failed for 'com.bridgeye.ejb.GenericCRUDServiceBean#com.bridgeye.ejb.GenericCRUDServiceBean' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: com.bridgeye.ejb.GenericCRUDServiceBean#com.bridgeye.ejb.GenericCRUDServiceBean not found]]]
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:518)
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:455)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl._inject(InjectionManagerImpl.java:597)

2) javax.rmi.Remote 和 javax.ejb.Remote 有什么区别?如果我取出注解 Remote,我的 EJB 是变成本地的还是必须用注解 Local 指定

3) 在我的托管 bean 中,我做了一个简单的 myEJB.find(User.class, id),但是如果我有 @TransactionAttribute(TransactionAttributeType.MANDATORY),那么我会遇到异常,如果我取出 TransactionAttribute 语句,它就可以正常工作。知道为什么吗?

【问题讨论】:

    标签: generics jakarta-ee ejb-3.0 crud


    【解决方案1】:
    1. EJB 容器实际上将创建一个基于代理的接口实现,该接口包装您的 bean 并添加事务和安全检查等内容。然后将此代理注入到带注释的字段中,这就是它需要具有接口类型的原因。我认为在 EJB 3.1 中,你可以省略接口而只有一个 bean 类,容器会创建一个子类来实现它的魔力。
    2. javax.ejb.Remote 是 EJB 3.0 注释,而 java.rmi.Remote 是 EJB 存在之前的普通接口。没有javax.rmi.Remote。你是对的,如果你不使用Remote注解,那么默认情况下EJB将被认为只有一个本地接口。
    3. 来自TransactionAttributeType.MANDATORY的API文档:

      如果客户调用企业 bean 的方法,而客户端是 与事务上下文相关联, 容器调用企业 客户端中bean的方法 事务上下文。

      如果没有现有的交易, 抛出异常。

      您可能想使用TransactionAttributeType.REQUIRED,如果不存在,它会自动启动一个事务,如果您使用不带参数的注释,它也是默认值。

    【讨论】:

      【解决方案2】:

      1.- 您的无状态 bean 暴露了接口 GenericCrudService(视图是应用程序服务器注册的内容),因此您使用

      @EJB
      private GenericCrudService myEJB;
      

      如果你有这个接口的多个实现,可以在注解中加上ejb名称进行消歧:

      @EJB(name="GenericCrudServiceBean")
      private GenericCrudService myEJB;
      

      在 EJB 3.1 中,没有接口的会话 Bean 公开了一种称为无接口视图的东西。这些会话 bean 只能在本地使用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-26
        • 1970-01-01
        • 1970-01-01
        • 2011-01-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多