javax.naming.NoInitialContextException:
Need to specify class name in environment or system property,
or as an applet parameter, or in an application resource file:
java.naming.factory.initial
程式碼在 **非 Servlet 容器執行緒** (如 main 方法、獨立類別、單元測試、排程器) 中直接 `new InitialContext()`,但未提供 JNDI 環境屬性 (Context.INITIAL_CONTEXT_FACTORY)。Tomcat 容器內部 (Servlet/Filter/Listener) 已自動配置,無需手動指定。
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory"); // Tomcat 專用
env.put(Context.URL_PKG_PREFIXES, "org.apache.naming");
InitialContext ctx = new InitialContext(env);
// 再 ctx.lookup("java:comp/env/jdbc/conn")
需將 `tomcat-embed-core` / `catalina.jar` 加入類路徑,複雜且脆弱。
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args); // 自動配置 DataSource、JNDI、連線池
}
}
@DataSourceDefinition(
name = "java:comp/env/jdbc/conn",
className = "com.mysql.cj.jdbc.Driver",
url = "jdbc:mysql://localhost:3306/exchange",
user = "root", password = "500235"
)
<!-- context.xml (在 META-INF/context.xml 或 conf/context.xml) -->
<Resource name="jdbc/conn"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory" <!-- DBCP2 -->
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/exchange?useSSL=false&serverTimezone=UTC"
username="root" password="500235"
maxTotal="20" maxIdle="10" maxWaitMillis="1000"/>
Servlet 3.0+ 無需 `web.xml` 定義 `
總結:JNDI 查找必須在容器初始化上下文中進行;獨立程式請改用框架自動配置或直接建立 DataSource Bean,勿硬編碼 InitialContext。