EJBUtil 核心功能
- 單例模式管理 `InitialContext`,避免重複建立開銷
- 封裝 WebLogic T3 協議連線參數 (`t3://localhost:7001`)
- 提供 EJB Home 查找、JDBC DataSource 取得連線的統一介面
- 異常統一包裝為 `EJBException` 簡化呼叫端處理
完整原始碼
package com.newmodern.etm.utility;
import java.util.*;
import javax.naming.*;
import javax.ejb.*;
import javax.rmi.PortableRemoteObject;
import javax.sql.*;
import java.sql.*;
public class EJBUtil {
private static Context context = null;
private static final String URL = "t3://localhost:7001";
private static final String JDBC_JNDI = "jdbc/XAOracle";
public static Object getEJBHome(String lookupName, Class homeClass) {
try {
if (context == null) context = getInitialContext();
Object home = PortableRemoteObject.narrow(context.lookup(lookupName), homeClass);
return home;
} catch (NamingException ne) {
throw new EJBException(ne.getMessage());
}
}
public static Connection getConnection(String lookupName) {
try {
if (context == null) context = getInitialContext();
DataSource ds = (DataSource) PortableRemoteObject.narrow(
context.lookup(lookupName), DataSource.class);
return ds.getConnection();
} catch (NamingException | SQLException e) {
throw new EJBException(e.getMessage());
}
}
public static Connection getConnection() {
return getConnection(JDBC_JNDI);
}
private static Context getInitialContext() throws NamingException {
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
props.put(Context.PROVIDER_URL, URL);
return new InitialContext(props);
}
}
實際呼叫範例
EJB Home 查找與建立實體
public void insertCategory(...) {
try {
CategoryHome home = (CategoryHome) EJBUtil.getEJBHome("MyMasterCategory", CategoryHome.class);
home.create(codeSubscriber, systemUsed, codeCategory, codeCategoryGroup, categoryDesc, actionBy, newTimestamp);
} catch (DuplicateKeyException e) { throw new ETMDataAlreadyExistsException(); }
catch (RemoteException | CreateException e) { throw new ETMDataAccessException(e); }
}
JDBC 連線池操作模板
public Collection getSubscriberList() {
Connection con = null;
PreparedStatement pStmt = null;
ResultSet res = null;
try {
con = EJBUtil.getConnection("jdbc/XAOracle");
pStmt = con.prepareStatement(subscriberSql);
res = pStmt.executeQuery();
while (res.next()) {
page.add(new SubscriberEntity(res.getString("code_subscriber"), res.getString("subscriber_name")));
}
} catch (SQLException e) { throw new ETMDataAccessException(e); }
finally {
// 標準資源關閉順序:ResultSet → Statement → Connection
closeQuietly(res); closeQuietly(pStmt); closeQuietly(con);
}
return page;
}
關鍵最佳實踐
- Context 重用:靜態快取 `InitialContext`,避免頻繁 JNDI 連線建立
- PortableRemoteObject.narrow():RMI-IIOP 環境下必須窄化轉型
- 資源關閉順序:`ResultSet` → `Statement` → `Connection`,並在 `finally` 區塊保證釋放
- 異常轉換:底層 `NamingException`/`SQLException` 包裝為應用層例外,隱藏實作細節
- 連線池透明化:業務碼無需感知 DataSource 設定細節,僅透過 JNDI 名稱取得連線
部署配置提醒
- WebLogic Console 中配置 `jdbc/XAOracle` XA DataSource,目標 Oracle 資料庫
- EJB `ejb-jar.xml` 中 `` 對應 `jdbc/XAOracle`
- Client 端 classpath 需包含 `weblogic.jar`、`wlclient.jar` 以支援 T3 協議