Разработка универсального компонента CRUD Session Bean - PullRequest
3 голосов
/ 13 апреля 2011

Этот вопрос был задан здесь однажды EJB 3 Session Bean Design для Simple 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) В моем управляемом бине я делаю простой myEJB.find(User.class, id), но если у меня есть @TransactionAttribute(TransactionAttributeType.MANDATORY), то я сталкиваюсь с исключением, все работает нормально, если я вынул оператор TransactionAttribute. Есть идеи почему?

Ответы [ 2 ]

6 голосов
/ 13 апреля 2011
  1. Контейнер EJB фактически создаст реализацию интерфейса на основе прокси, которая оборачивает ваш компонент и добавляет такие вещи, как транзакции и проверки безопасности.Затем этот прокси-сервер вводится в аннотированное поле, поэтому ему необходимо иметь тип интерфейса.Я думаю, что в EJB 3.1 вы можете опустить интерфейс и иметь только класс компонента, и контейнер создаст подкласс для реализации его магии.
  2. javax.ejb.Remote - это аннотация EJB 3.0, а java.rmi.Remote - этопростой интерфейс до того, как существовали EJB.Там нет javax.rmi.Remote.И вы правы, если вы не используете аннотацию Remote, то по умолчанию EJB будет считаться имеющим только локальный интерфейс.
  3. Из документа API TransactionAttributeType.MANDATORY:

    Если клиент вызывает метод корпоративного компонента, в то время как клиент связан с контекстом транзакции, контейнер вызывает метод корпоративного компонента в контексте транзакции клиента.

    Если не существует существующеготранзакция, исключение выдается.

    Возможно, вы захотите использовать TransactionAttributeType.REQUIRED, который автоматически запускает транзакцию, если ее нет, и также используется по умолчанию, если вы используете аннотацию без параметра.

0 голосов
/ 14 апреля 2011

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

@EJB
private GenericCrudService myEJB;

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

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

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

...