Java Swing升级至Java17+Maven后窗口无法正常加载求助
Java Swing项目升级Java17+Maven后界面异常排查
问题现象
原本基于Java8+Ant运行正常的Swing项目,升级为Java17+Maven(Netbeans IDE)后,启动仅显示极小窗口,预期组件全部缺失;手动放大窗口后界面仍异常。
当前Maven依赖(pom.xml)
<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.30</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.11.1</version> </dependency> <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.8.0</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> <optional>true</optional> </dependency> </dependencies>
原Ant项目依赖说明
原项目使用的库包含mysql驱动、commons-dbcp、commons-pool、commons-net、commons-lang3等类库。
核心启动代码
PrincipalLayout构造方法
public PrincipalLayout() { this.service = new ProductService(); //La base de datos esta vacia this.model = new TableModel(service.selectAllProducts()); }
ProductService构造方法
private final InMemoryProductRepository mysqlController; private List<Product> inMemoryList; public ProductService(){ this.mysqlController = new InMemoryProductRepository(); var optionalProducts = mysqlController.selectAll(); if(optionalProducts.isPresent()) optionalProducts.get().forEach(p-> this.inMemoryList.add( p)); if(optionalProducts.isEmpty()) this.inMemoryList.addAll(Collections.emptyList()) }
Repository的selectAll方法
@Override public Optional<List<Product>> selectAll() { List<Product> products = Collections.emptyList(); try { PreparedStatement preparedStatement = ConnectionJDBC .getConnection().prepareStatement(SQL_SELECT.getCommand()); ResultSet resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { var product = new Product( resultSet.getInt("product_id"), resultSet.getString("name"), resultSet.getDouble("price") ); products.add(product); } ConnectionJDBC.close(resultSet); ConnectionJDBC.close(preparedStatement); ConnectionJDBC.close(ConnectionJDBC.getConnection()); } catch (SQLException ex) { JOptionPane.showMessageDialog(null, "Ocurrio un error al ejecutar SellectAll", "ERROR", 0); } return Optional.of(products); }
排查方向
- Swing线程违规:Java17对Swing UI线程规范要求更严格,检查是否所有UI初始化代码都在
EventQueue.invokeLater()或SwingUtilities.invokeLater()中执行。原Ant项目可能直接在主线程初始化UI,Java17下会导致渲染异常。 - 数据库操作阻塞UI线程:
PrincipalLayout构造方法直接调用数据库查询,会阻塞UI线程导致窗口无法正常渲染,必须将数据库操作移到后台线程。 - 空指针异常隐藏:
ProductService中inMemoryList未初始化就调用add/addAll,会抛出空指针但可能被线程异常吞掉,导致UI初始化中断。 - 依赖版本兼容:检查Maven依赖是否与原Ant项目版本一致,尤其是commons-dbcp2、mysql驱动是否存在Java17兼容性问题;原项目可能使用commons-dbcp而非dbcp2,两者API存在差异。
- 连接池资源泄漏:
selectAll中多次调用ConnectionJDBC.getConnection(),可能获取多个连接,且关闭逻辑存在风险(若getConnection()每次返回新实例,最后关闭的不是当前使用的连接)。
代码优化建议
修复空指针问题:
在ProductService中初始化集合:private List<Product> inMemoryList = new ArrayList<>(); // 或在构造方法内初始化 public ProductService(){ this.mysqlController = new InMemoryProductRepository(); this.inMemoryList = new ArrayList<>(); var optionalProducts = mysqlController.selectAll(); optionalProducts.ifPresent(products -> this.inMemoryList.addAll(products)); }将数据库操作移到后台线程:
使用SwingWorker异步加载数据,避免阻塞UI:public PrincipalLayout() { initComponents(); // 先初始化UI框架 new SwingWorker<List<Product>, Void>() { @Override protected List<Product> doInBackground() throws Exception { ProductService service = new ProductService(); return service.selectAllProducts(); } @Override protected void done() { try { List<Product> products = get(); model = new TableModel(products); table.setModel(model); // 更新UI组件 } catch (Exception ex) { JOptionPane.showMessageDialog(null, "加载数据失败", "ERROR", JOptionPane.ERROR_MESSAGE); } } }.execute(); }修复数据库连接管理:
使用try-with-resources自动关闭资源,确保连接一致性:@Override public Optional<List<Product>> selectAll() { List<Product> products = new ArrayList<>(); try (Connection conn = ConnectionJDBC.getConnection(); PreparedStatement preparedStatement = conn.prepareStatement(SQL_SELECT.getCommand()); ResultSet resultSet = preparedStatement.executeQuery()) { while (resultSet.next()) { var product = new Product( resultSet.getInt("product_id"), resultSet.getString("name"), resultSet.getDouble("price") ); products.add(product); } } catch (SQLException ex) { JOptionPane.showMessageDialog(null, "执行查询时出错", "ERROR", JOptionPane.ERROR_MESSAGE); ex.printStackTrace(); } return Optional.of(products); }确保UI线程安全:
主方法中强制在EDT线程启动UI:public static void main(String[] args) { EventQueue.invokeLater(() -> { new PrincipalLayout().setVisible(true); }); }对齐依赖版本:
若原项目使用commons-dbcp而非dbcp2,替换Maven依赖:<dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency>
内容的提问来源于stack exchange,提问作者Marcos Lopez
相关产品推荐
相关产品推荐

