首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

跨服務器調用 EJB 實戰指南:JNDI 遠程查找配置與 Client Stub 部署詳解

     編輯:Java 相關知識

場景:Web 模塊 (Server B) 調用 EJB 服務 (Server A)

典型分佈式部署架構:Web 容器 (Tomcat/Jetty/獨立 WebLogic) 與 EJB 容器 (WebLogic/WebSphere/JBoss) 分離部署。核心挑戰:JNDI 遠程查找配置 與 Client Stub 類可用性。

核心步驟一:配置 JNDI InitialContext 環境屬性

客戶端 (Web 模塊) 必須告知 JNDI 服務提供者 (EJB 容器) 的位置與協議。

方式 1:Properties + 廠商專有工廠 (Sun ONE / GlassFish / WebLogic 兼容)

Properties env = new Properties();
env.put("java.naming.factory.initial", "com.sun.jndi.cosnaming.CNCtxFactory"); // Sun CORBA Naming
env.put("java.naming.provider.url", "iiop://192.168.0.2:3700"); // EJB 容器 IIOP 監聽地址
// 可選:安全憑證
// env.put("java.naming.security.principal", "ejbuser");
// env.put("java.naming.security.credentials", "ejbpwd");

Context ctx = new InitialContext(env);

方式 2:Hashtable + 標準常量 (更規範)

Hashtable env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory");
env.put(Context.PROVIDER_URL, "iiop://192.168.0.2:3700");
// WebLogic 專用工廠 (若調用 WebLogic EJB)
// env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
// env.put(Context.PROVIDER_URL, "t3://192.168.0.2:7001");

Context ctx = new InitialContext(env);

關鍵參數說明

參數說明常見值
java.naming.factory.initialJNDI SPI 實現類,決定協議 (IIOP/T3/HTTP)Sun: com.sun.jndi.cosnaming.CNCtxFactory
WebLogic: weblogic.jndi.WLInitialContextFactory
JBoss: org.jnp.interfaces.NamingContextFactory (Legacy) / org.wildfly.naming.client.WildFlyInitialContextFactory (EJB Client API)
java.naming.provider.url命名服務端點 (IP:Port)iiop://host:port (標準 CORBA)
t3://host:port (WebLogic 專有)
https://host:port (HTTP 穿透)
java.naming.security.principal/credentials安全認證 (若 EJB 啟用安全)用戶名/密碼

核心步驟二:部署 Client Stub / 接口 JAR 到 Web 模塊

原理:RMI-IIOP 遠程調用需要客戶端持有 Stub (存根) 類,負責序列化參數、發送 IIOP 請求、反序列化返回值。Stub 類在 EJB 部署時由容器工具 (如 appc, ejbc, rmic -iiop) 自動生成。

必須部署的文件

  • EJB Remote 接口 (如 MyServiceRemote.java)。
  • EJB Home 接口 (如 MyServiceHome.java) —— EJB 2.x 必需。
  • Stub 類 (如 MyServiceRemote_Stub.class, MyServiceHome_Stub.class)。
  • 相關 值類型/異常類 (傳遞的參數/返回值類)。

部署位置

WebApp.war
└── WEB-INF/
    └── lib/
        └── my-ejb-client.jar   <-- 打包上述所有接口 + Stub 類

注意:不要** 將 EJB 實現類 (Bean 類) 打包到 Client JAR,僅需接口與 Stub。

完整調用代碼示例

public class EJBClientServlet extends HttpServlet {
    private MyServiceRemote service;

    public void init() throws ServletException {
        try {
            // 1. 構建 JNDI 環境 (可從 web.xml context-param 讀取)
            Properties env = new Properties();
            env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
            env.put(Context.PROVIDER_URL, "t3://192.168.0.2:7001");
            Context ctx = new InitialContext(env);

            // 2. 查找 Home 接口
            Object homeRef = ctx.lookup("ejb/MyService"); // JNDI 名稱需與 EJB 部署一致
            MyServiceHome home = (MyServiceHome) PortableRemoteObject.narrow(homeRef, MyServiceHome.class);

            // 3. 創建 Remote 業務代理
            service = home.create();
        } catch (Exception e) {
            throw new ServletException("EJB 初始化失敗", e);
        }
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        try {
            String result = service.doBusiness(req.getParameter("param"));
            resp.getWriter().println("EJB 調用結果: " + result);
        } catch (RemoteException e) {
            resp.sendError(500, "EJB 遠程調用失敗: " + e.getMessage());
        }
    }
}

常見故障排查清單

現象可能原因解決方案
ClassNotFoundException: ..._StubClient JAR 缺少 Stub 類重新編譯/部署 EJB 生成 Stub,打包進 WEB-INF/lib
ClassCastException: ... cannot be cast to MyServiceHomeStub 版本不匹配 / 接口不一致確保 Client JAR 與 EJB 部署版本完全一致;清理緩存重新部署
CommunicationException / ConnectException網絡不通 / 端口錯誤 / 防火牆telnet IP Port 驗證;檢查 PROVIDER_URL 協議/端口;關閉防火牆或開放端口
NoClassDefFoundError: org/omg/CORBA/...客戶端缺少 CORBA 運行時庫WebLogic: 添加 wlclient.jar; WildFly: 添加 wildfly-ejb-client-bom 依賴
SecurityException / AuthenticationFailed安全憑證缺失/錯誤在 env 中設置 principal/credentials;或配置 SSL 互信

現代替代方案:EJB 3.1+ 無接口視圖 / REST / gRPC

  • EJB 3.1 No-Interface View:本地調用無需 Home/Remote,直接 @EJB MyService service 注入。跨服務器仍需 Remote 接口。
  • JAX-RS (REST):EJB 暴露 @Path 資源,Web 端用 HttpClient/RestTemplate 調用,**無需 Stub,防火牆友好,異構語言互通**。
  • gRPC:定義 .proto,生成多語言 Stub,性能極佳,適合微服務架構。

總結

跨服務器調用 EJB 核心在於:**正確的 JNDI 初始化參數 (工廠類 + IIOP/T3 URL) + 完整的 Client Stub JAR 部署**。掌握此機制,是維護傳統 J2EE 分佈式系統、進行微服務化拆分前的必備技能。新架構建議遷移至 REST/gRPC,降低耦合與運維複雜度。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved