Разработка универсального сеансового компонента CRUD

Этот вопрос задавали однажды здесь Дизайн сессионного компонента EJB 3 для простого CRUD, и я просто хочу задать более подробные вопросы об этом дизайне. Я уже пытался задать вопросы в исходном посте, но не получил ответа, поэтому решил создать новый пост. Итак, решение Pascal для реализации общего сеансового компонента CRUD выглядит следующим образом

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) Когда я пытаюсь сослаться на этот EJB-компонент в моем управляемом bean-компоненте, я должен сделать

@EJB
private GenericCrudService myEJB;

вместо

@EJB
private GenericCrudServiceBean myEJB;

Для меня это не имеет особого смысла, поскольку GenericCrudService - это просто интерфейс, GenericCrudServiceBean - компонент без сохранения состояния.

Я получаю это исключение, когда делаю 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 оператор. Есть идеи, почему?


person Thang Pham    schedule 12.04.2011    source источник


Ответы (2)


  1. Контейнер EJB фактически создаст реализацию интерфейса на основе прокси, которая обертывает ваш bean-компонент и добавляет такие вещи, как транзакции и проверки безопасности. Затем этот прокси вводится в аннотированное поле, поэтому он должен иметь тип интерфейса. Я думаю, что в EJB 3.1 вы можете опустить интерфейс и иметь только класс bean, а контейнер создаст подкласс для реализации своей магии.
  2. javax.ejb.Remote - это аннотация EJB 3.0, а java.rmi.Remote - простой интерфейс, созданный до того, как EJB существовали. Нет javax.rmi.Remote. И вы правы, если вы не используете аннотацию Remote, то по умолчанию будет считаться, что EJB имеет только локальный интерфейс.
  3. # P1 #
    # P2 # # P3 #
    # P4 #
person Michael Borgwardt    schedule 12.04.2011

1.- Ваш bean-компонент без сохранения состояния предоставляет интерфейс GenericCrudService (представление - это то, что регистрирует сервер приложений), по этой причине вы используете

@EJB
private GenericCrudService myEJB;

Если у вас есть несколько реализаций этого интерфейса, вы можете добавить имя ejb в аннотацию для устранения неоднозначности:

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

В EJB 3.1 Session Bean без интерфейса предоставляет нечто, называемое представлением без интерфейса. Эти сессионные компоненты можно использовать только локально.

person victor herrera    schedule 14.04.2011