本篇深入剖析雙介面 EJB 專案的 JNDI 綁定配置細節、部署描述符關鍵片段與核心 Java 實現邏輯,揭示 useLocal 環境變數如何動態控制介面路由,以及 Servlet 與 Session Bean 如何透過 JNDI 查找建立通訊鏈路。
DualEntity。ejb/dual/ejb/DualEntityHome。<env-entry>
<env-entry-name>useLocal</env-entry-name>
<env-entry-type>java.lang.Boolean</env-entry-type>
<env-entry-value>true</env-entry-value>
</env-entry>
<env-entry>
<env-entry-name>doTrace</env-entry-name>
<env-entry-type>java.lang.Boolean</env-entry-type>
<env-entry-value>false</env-entry-value>
</env-entry>
<ejb-ref> <!-- 遠端介面引用 -->
<ejb-ref-name>ejb/DualEntityRemoteHome</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<home>dual.ejb.DualEntityRemoteHome</home>
<remote>dual.ejb.DualEntityRemote</remote>
<ejb-link>DualEJBModule01.jar#DualEntity</ejb-link>
</ejb-ref>
<ejb-local-ref> <!-- 本地介面引用 -->
<ejb-ref-name>ejb/DualEntityLocalHome</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<local-home>dual.ejb.DualEntityLocalHome</local-home>
<local>dual.ejb.DualEntityLocal</local>
<ejb-link>DualEJBModule01.jar#DualEntity</ejb-link>
</ejb-local-ref>
關鍵點:
useLocal 控制介面選擇;doTrace 控制除錯輸出。ejb-ref (遠端) 與 ejb-local-ref (本地),透過 ejb-link 關聯同一實體 Bean。public class DualSessionBean implements javax.ejb.SessionBean {
private javax.ejb.SessionContext mySessionCtx;
private boolean doTrace, useLocal;
private DualEntityRemoteHome entityRemoteHome;
private DualEntityLocalHome entityLocalHome;
public void setSessionContext(javax.ejb.SessionContext ctx) {
mySessionCtx = ctx;
try {
Context initCtx = new InitialContext();
Boolean option = null;
// 讀取環境變數
option = (Boolean) initCtx.lookup("java:comp/env/useLocal");
useLocal = option.booleanValue();
option = (Boolean) initCtx.lookup("java:comp/env/doTrace");
doTrace = option.booleanValue();
if (doTrace)
System.out.println("DualSessionBean#setSessionContext: useLocal=" + useLocal);
Object homeObject = null;
if (useLocal) {
// 本地介面:直接窄化
homeObject = initCtx.lookup("java:comp/env/ejb/DualEntityLocalHome");
entityLocalHome = (DualEntityLocalHome) homeObject;
} else {
// 遠端介面:需 PortableRemoteObject.narrow
homeObject = initCtx.lookup("java:comp/env/ejb/DualEntityRemoteHome");
entityRemoteHome = (DualEntityRemoteHome)
javax.rmi.PortableRemoteObject.narrow(homeObject, DualEntityRemoteHome.class);
}
} catch (NamingException ne) { /* 異常處理 */ }
}
// ... 業務方法根據 useLocal 委派給 entityLocalHome 或 entityRemoteHome
}
設計精華:
PortableRemoteObject.narrow (RMI-IIOP 規範要求)。ejb/dual/ejb/DualSessionHome。DualEntity 的兩個引用 (遠端/本地) 皆指向 JNDI ejb/dual/ejb/DualEntityHome。<context-param>
<param-name>useLocal</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>doTrace</param-name>
<param-value>true</param-value>
</context-param>
<!-- 分離容器架構需用的參數,此處註解掉 -->
<!--
<context-param>
<param-name>ejbHost</param-name>
<param-value>localhost</param-value>
</context-param>
<context-param>
<param-name>ejbPort</param-name>
<param-value>2809</param-value>
</context-param>
<context-param>
<param-name>useLocal</param-name>
<param-value>false</param-value>
</context-param>
-->
<ejb-ref> <!-- 遠端會話 Bean 引用 -->
<ejb-ref-name>ejb/DualSessionRemoteHome</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home>dual.ejb.DualSessionRemoteHome</home>
<remote>dual.ejb.DualSessionRemote</remote>
<ejb-link>DualEJBModule02.jar#DualSession</ejb-link>
</ejb-ref>
<ejb-local-ref> <!-- 本地會話 Bean 引用 -->
<ejb-ref-name>ejb/DualSessionLocalHome</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local-home>dual.ejb.DualSessionLocalHome</local-home>
<local>dual.ejb.DualSessionLocal</local>
<ejb-link>DualEJBModule02.jar#DualSession</ejb-link>
</ejb-local-ref>
public class DualServlet extends HttpServlet {
private static final String JNDI_NAME_LOCAL = "java:comp/env/ejb/DualSessionLocalHome";
private static final String JNDI_NAME_REMOTE = "java:comp/env/ejb/DualSessionRemoteHome";
private boolean useLocal, doTrace;
private DualSessionLocalHome sessionLocalHome;
private DualSessionRemoteHome sessionRemoteHome;
public void init() throws ServletException {
super.init();
// 讀取 context-param
ServletContext ctx = getServletContext();
useLocal = Boolean.valueOf(ctx.getInitParameter("useLocal")).booleanValue();
doTrace = Boolean.valueOf(ctx.getInitParameter("doTrace")).booleanValue();
try {
Context initCtx = new InitialContext();
Object homeObject = null;
if (useLocal) {
homeObject = initCtx.lookup(JNDI_NAME_LOCAL);
sessionLocalHome = (DualSessionLocalHome) homeObject;
} else {
homeObject = initCtx.lookup(JNDI_NAME_REMOTE);
sessionRemoteHome = (DualSessionRemoteHome)
PortableRemoteObject.narrow(homeObject, DualSessionRemoteHome.class);
}
} catch (NamingException ne) { throw new ServletException(ne); }
}
// doGet/doPost 中根據 useLocal 呼叫 sessionLocalHome 或 sessionRemoteHome.create()
}
註:下載原始碼中包含分離容器拓撲的額外參數處理邏輯 (ejbHost/ejbPort),此處簡化。
DualServlet 設置 → References 分頁。ejb/dual/ejb/DualSessionHome。| 專案 | 依賴專案 (Java Build Path / Project References / Web Library Projects) |
|---|---|
| DualJavaModule00 | 無 |
| DualEJBModule01 | 無 |
| DualEJBModule02 | DualJavaModule00、DualEJBModule01 |
| DualWebModule03 | DualJavaModule00、DualEJBModule02 |
| DualEARForEJBContainer | DualJavaModule00、DualEJBModule01、DualEJBModule02 (EAR 描述符引用 EJB/JAVA 模組) |
| DualEARForAllInOne | 所有模組 |
正確配置依賴後,編譯錯誤應自動消失。