首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Servlet "execution threw an exception" 排查:DBConn 靜態塊初始化異常導致的空指針連鎖反應

     編輯:程式設計綜合問答

現象描述

Servlet 拋出 `Servlet execution threw an exception`,根因指向 `DBConn` 類初始化。

代碼缺陷分析


public class DBConn {
    static {
        try {
            // ❌ 這行無意義
            DBConn.class.getClassLoader();  
            
            InputStream in = ClassLoader.getSystemResourceAsStream("joggle.properties");
            // ❌ 若文件不在 classpath 根目錄,in 為 null
            Properties prop = new Properties();
            prop.load(in);  // ❌ NPE:in 為 null
            // ...
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);  // 包裝拋出
        }
    }
    // ...
}

錯誤鏈路

  1. `joggle.properties` 未放在 `src/main/resources` 或編譯輸出目錄
  2. `getSystemResourceAsStream` 返回 `null`
  3. `prop.load(null)` 拋出 `NullPointerException`
  4. 靜態塊捕獲並包裝為 `ExceptionInInitializerError`
  5. 類初始化失敗,後續調用 `DBConn.getConnection()` 拋出 `NoClassDefFoundError`
  6. Servlet 線程捕獲並包裝為 `Servlet execution threw an exception`

修正方案


public class DBConn {
    private static final Logger log = LoggerFactory.getLogger(DBConn.class);
    private static final String PROP_FILE = "jdbc.properties";  // 建議標準名
    
    static {
        try (InputStream in = DBConn.class.getClassLoader().getResourceAsStream(PROP_FILE)) {
            if (in == null) {
                throw new RuntimeException("配置文件未找到: " + PROP_FILE + ",請放置在 classpath 根目錄");
            }
            Properties prop = new Properties();
            prop.load(in);
            
            driverName = prop.getProperty("driverName");
            dbURL = prop.getProperty("dbURL");
            userName = prop.getProperty("userName");
            password = prop.getProperty("password");
            
            Class.forName(driverName);
            log.info("數據庫驅動加載成功: {}", driverName);
        } catch (Exception e) {
            log.error("DBConn 初始化失敗", e);
            throw new ExceptionInInitializerError(e);
        }
    }
    
    // 連接池建議使用 HikariCP / Druid,而非手寫
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(dbURL, userName, password);
    }
}

配置文件放置位置


Maven 標準結構:
src/
  main/
    resources/
      jdbc.properties   ← 這裡
    java/
      com/...
        DBConn.java

jdbc.properties 模板


driverName=com.mysql.cj.jdbc.Driver
dbURL=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
userName=root
password=123456

生產級建議:棄用手寫 DBConn,上連接池




    com.zaxxer
    HikariCP
    5.0.1


// Spring 配置
@Bean
public DataSource dataSource() {
    HikariConfig config = new HikariConfig();
    config.setJdbcUrl(dbURL);
    config.setUsername(userName);
    config.setPassword(password);
    config.setDriverClassName(driverName);
    config.setMaximumPoolSize(20);
    return new HikariDataSource(config);
}

總結

`ExceptionInInitializerError` 包裝了真實異常(此處為 NPE)。**關鍵定位:查看 `Caused by` 鏈最底層的異常**。配置文件路徑、靜態塊異常處理、資源流關閉、遷移到成熟連接池,四步徹底解決。

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