2016-04-07 73 views
0

我想用EclipseLink和OpenEJB實現描述爲here的DAO模式。鏈接中列出的圖9.1的第一次嘗試正常工作。代碼如下:如何使EntityManager在DAO工廠中正常工作?

// 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異常。當我用調試器跟蹤代碼時,我發現EntityManager in OracleCustomerDAOnull。我認爲這是因爲我沒有在我的新服務中進行任何@EJB注射,但我不知道我在哪裏可以放入@EJB注射劑。

那麼注入一個EntityManager與DAO工廠模式的正確方法是什麼?

回答

1

爲了使EJB的行爲與EJB類似,您不應該創建它們。 EJB容器負責創建它們,確保每個裝飾(事務,注入)都正確應用。

EJB容器已經爲您實現了工廠模式。您應該使用它的功能來獲得特定的實現(我沒有使用獨立的openEJB的經驗,但是在完整的Java EE環境中,CDI和JNDI提供了所需的功能)。

看來您應該可以使用JNDI來檢索預期的EJB。

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

full doc

對於CDI的方式,你可以用它替代機制(TommEE doc):如果EJB的名稱是默認的類名

此代碼應工作。

關於模式的一句話。他們應該用來解決一個痛點。已經記錄了J2EE模式以克服J2EE的限制。在未來的Java EE發行版中,它們引入了一個元素,它以一種更實用的方式實現了不同的模式。 JAP是其中的一部分。

JPA是Domain Store pattern的實現。在Domain Store圖中,您可以清楚地看到它已經包含DAO。那麼,在已經包含DAO的抽象之上創建DAO有什麼意義?

+0

感謝您的回答,我會閱讀文檔並嘗試修改我的代碼以使其有效(如果我成功,我會接受答案,否則我會在評論中更新狀態)。在模式部分,我讀了很多關於JPA如何殺死DAO的主題,並且對此有不同的看法。我仍然不確定DAO模式是否與JPA一致,也許有一天公司希望擺脫JPA,並且DAO模式將更容易重構,因爲它將邏輯部分和數據操作部分分開了? – Nier

+0

如果您將JPA替換爲其他框架,那麼您的「DAO」抽象將不再可用的機率爲9.99%,您將需要使用它更新DAO接口和業務邏輯。在業務邏輯中替換JPA使用的時間將比自己的DAO花費更多時間。如果你需要在某個地方做一些JPA魔術,你可以在分離的類中抽象這個部分。但JPA使用率的95%是簡單的CRUD,可以直接更新。 – Kazaag

+0

我用'return(CustomerDAO)new InitialContext()。lookup(「java:comp/env/OracleCustomerDAO」)替換'return new OracleCustomerDAO();''getCustomerDAO()''函數。然而,它給了我一個'NamingException',其中說**名稱「comp/env/OracleCustomerDAO」找不到。** – Nier