Hibernate 的 JNDI 綁定發生在 Configuration.buildSessionFactory() 過程中,由 SessionFactoryObjectFactory 完成。理解此機制有助於在應用伺服器中正確管理 SessionFactory 生命週期。
Configuration conf = new Configuration().addClass(Cat.class);
// 建構子內讀取 hibernate.properties,屬性存入 Properties 物件
// 關鍵屬性:hibernate.session_factory_name = hibernate/session_factory
SessionFactory sf = conf.buildSessionFactory();
// 內部檢查配置 → 呼叫 SessionFactoryImpl 建構子
name = properties.getProperty(Environment.SESSION_FACTORY_NAME);
SessionFactoryObjectFactory.addInstance(uuid, name, this, properties);
name:從屬性讀取 JNDI 名稱 (預設 hibernate/session_factory)this:SessionFactory 實例自身SessionFactoryObjectFactory.addInstance()Context ctx = NamingHelper.getInitialContext(properties);
NamingHelper.bind(ctx, name, instance);
NamingHelper 取得 JNDI InitialContextconf.buildSessionFactory() 執行時自動完成 JNDI 綁定load-on-startup 的初始化 Servlet 執行建立代碼hibernate.session_factory_name = java:/hibernate/SessionFactory
hibernate.jndi.url = jnp://localhost:1099
hibernate.jndi.class = org.jnp.interfaces.NamingContextFactory
<servlet>
<servlet-name>HibernateInitializer</servlet-name>
<servlet-class>com.example.HibernateInitServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
public class HibernateInitServlet extends HttpServlet {
public void init() {
Configuration conf = new Configuration().configure();
conf.buildSessionFactory(); // 觸發 JNDI 綁定
}
}
| 問題 | 原因 | 解決方案 |
|---|---|---|
| JNDI 查找失敗 (NameNotFoundException) | SessionFactory 尚未建立/綁定 | 確保初始化 Servlet/服務優先啟動,檢查 load-on-startup 順序 |
| 多個 SessionFactory 綁定衝突 | 同名綁定覆蓋 | 為每個資料來源配置唯一的 hibernate.session_factory_name |
| 應用重新部署後 JNDI 殘留舊實例 | 未正確解綁 | 實作 ServletContextListener.contextDestroyed() 呼叫 SessionFactoryObjectFactory.removeInstance() |
| 叢集環境 JNDI 不可用 | 預設 JNDI 非叢集感知 | 使用應用伺服器叢集 JNDI (如 HA-JNDI) 或改用本地查找模式 |
JPA / Spring Framework / CDI 等現代框架提供更優雅的 SessionFactory/EntityManager 管理與注入機制,建議新專案優先考慮:
LocalSessionFactoryBean + <jee:jndi-lookup>@PersistenceUnit / @PersistenceContext