【问题标题】:How to make EntityManager works properly in DAO Factories?如何使 EntityManager 在 DAO 工厂中正常工作?
【发布时间】:2016-04-07 08:20:48
【问题描述】:

我想用 EclipseLink 和 OpenEJB 实现描述 here 的 DAO 模式。链接中列出的图 9.1 的第一次尝试工作正常。代码如下:

// CustomerDAO
@Local
public interface CustomerDAO {
    Customer findCustomer(String id);
}

// OracleCustomerDAO
@Stateless
@Local(CustomerDAO.class)
@TransactionManagement(TransactionManagementType.CONTAINER)
public class OracleCustomerDAO implements CustomerDAO {

    @PersistenceContext(unitName = "MY_EJB")
    private EntityManager em;

    public Customer findCustomer(String id) {
        return em.find(Customer.class, id);
    }
}

在我的服务中:

public class CustomerService implements CustomerServiceLocal {
    @EJB
    CustomerDAO customerDAO;

    public Customer findCustomer(String id) {
        return customerDAO.findCustomer(id);
    }
}

但是,当我想适应工厂模式时,我不知道什么是正确的方法。我在链接中编写了代码作为教程,并添加了两个这样的类:

// DAOFactory
public abstract class DAOFactory {
    public abstract CustomerDAO getCustomerDAO();

    public enum Factory {
        ORACLE;
    }

    public static DAOFactory getDaoFactory(Factory whichFactory) {
        switch (whichFactory) {
        case ORACLE:
            return new OracleDAOFactory();
            break;
        default:
            break;
        }
    }
}

// OracleDAOFactory
public class OracleDAOFactory extends DAOFactory {

    @Override
    public CustomerDAO getCustomerDAO() {
        return new OracleCustomerDAO();
    }

}

我将我的服务修改为:

public class CustomerService implements CustomerServiceLocal {

    public Customer findCustomer(String id) {

        CustomerDAO customerDAO = DAOFactory.getDaoFactory(Factory.ORACLE).getCustomerDAO();

        return customerDAO.findCustomer(id);
    }
}

这给了我一个 NullPointerException。当我使用调试器跟踪代码时,我发现OracleCustomerDAO 中的EntityManagernull。我认为这是因为我没有在我的新服务中进行任何@EJB 注入,但我不知道该将@EJB 注入放在哪里。

那么用 DAO 工厂模式注入 EntityManager 的正确方法是什么?

【问题讨论】:

    标签: java jpa eclipselink dao openejb


    【解决方案1】:

    为了让 EJB 表现得像 EJB,你不应该创建它们。 EJB 容器负责创建它们以确保正确应用每个修饰(事务、注入)。

    EJB 容器已经为您实现了工厂模式。您应该使用它的功能来获得特定的实现(我没有使用独立的 openEJB 的经验,但在完整的 Java EE 环境中,CDI 和 JNDI 提供了所需的功能)。

    看来您应该能够使用 JNDI 来检索预期的 EJB。

    如果 EJB 的名称默认为类名,则此代码应该可以工作:

    CustomerDAO friend = (CustomerDAO) new InitialContext().lookup("java:comp/env/OracleCustomerDAO");
    

    (full doc)

    对于 CDI 方式,您可以使用其替代机制 (TommEE doc)。

    关于模式的一点点。它们应该用于解决痛点。 J2EE 模式已被记录以克服 J2EE 的限制。在 Java EE 的未来版本中,他们引入了元素,以更可用的方式实现不同的模式。 JAP 是其中的一部分。

    JPA 是Domain Store pattern 的实现。在 Domain Store 图中,您可以清楚地看到它已经包含 DAO。那么在已经包含 DAO 的抽象之上创建 DAO 有什么意义呢?

    【讨论】:

    • 感谢您的回答,我将阅读文档并尝试修改我的代码以使其正常工作(如果成功,我将接受答案,或者我将在评论中更新状态)。在模式部分,我阅读了很多关于 JPA 如何杀死 DAO 之类的话题,对此有很多不同的看法。我仍然不确定DAO模式与JPA是否好,也许有一天公司想摆脱JPA,DAO模式将更容易重构,因为它将逻辑部分和数据操作部分分开?
    • 如果您将 JPA 替换为其他框架,9.99% 的机会您的“DAO”抽象将不再工作,您将需要更新 DAO 接口和使用它的业务逻辑。在业务逻辑中替换 JPA 的使用将比在其自身的 DAO 中花费更多的时间。如果你需要在某个地方做一些 JPA 魔术,你可以在分离的类中抽象这部分。但是 95% 的 JPA 使用都是简单的 CRUD,可以直接更新。
    • 我在 getCustomerDAO() 函数中用 return (CustomerDAO) new InitialContext().lookup("java:comp/env/OracleCustomerDAO"); 替换了 return new OracleCustomerDAO();。但是它给了我一个 NamingException,上面写着 Name "comp/env/OracleCustomerDAO" not found。
    • 我也尝试将@EJB(name="OracleCustomerDAO", beanInterface=CustomerDAO.class) 放在OracleDAOFactory 类定义的上方,但没有帮助。
    • 您在哪里检索 EJB?如果它不是来自同一容器中的其他 EJB,则 JNDI 名称将不同。示例和示例上的测试日志显示了已创建的 EJB 及其名称。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-04
    • 2012-04-19
    • 1970-01-01
    相关资源
    最近更新 更多