You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ConnectionFactory单例类无法读取application.properties属性的解决方法

解决单例ConnectionFactory无法读取application.properties属性的问题

问题原因

你手动通过静态内部类创建的ConnectionFactory实例不属于Spring容器管理范畴,Spring无法为该实例的@Value注解字段注入配置值,因此这些属性始终为null。此外,代码中@Value("${spring.datasource.user}")与配置文件的spring.datasource.username键名不匹配,也会导致注入失败。

解决方案

方案一:将ConnectionFactory改为Spring管理的Bean(推荐)

把类交给Spring容器管理,利用Spring的依赖注入机制完成配置属性注入,同时调整初始化逻辑到@PostConstruct方法(确保注入完成后再初始化数据源)。

修改后的ConnectionFactory代码:

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnection;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;

@Component
public class ConnectionFactory {

    private DataSource dataSource;

    // 修正键名,与配置文件保持一致
    @Value("${spring.datasource.username}")
    private String user;
    @Value("${spring.datasource.password}")
    private String password;
    @Value("${spring.datasource.url}")
    private String url;

    // 注入完成后初始化数据源
    @PostConstruct
    public void initDataSource() {
        Properties properties = new Properties();
        properties.setProperty("user", user);
        properties.setProperty("password", password);

        GenericObjectPool<PoolableConnection> pool = new GenericObjectPool<>();
        DriverManagerConnectionFactory connectionFactory = new DriverManagerConnectionFactory(
                url, properties
        );
        new PoolableConnectionFactory(
                connectionFactory, pool, null, "SELECT 1", 3, false, false, Connection.TRANSACTION_READ_COMMITTED
        );

        this.dataSource = new PoolingDataSource(pool);
    }

    public Connection getDatabaseConnection() throws SQLException {
        return dataSource.getConnection();
    }
}

使用方式:通过Spring依赖注入获取实例

@Autowired
private ConnectionFactory connectionFactory;

// 获取连接
Connection conn = connectionFactory.getDatabaseConnection();

如果需要保留静态方法获取连接,可以实现ApplicationContextAware接口获取Spring容器实例:

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class ConnectionFactory implements ApplicationContextAware {

    private static ConnectionFactory instance;
    private DataSource dataSource;

    @Value("${spring.datasource.username}")
    private String user;
    @Value("${spring.datasource.password}")
    private String password;
    @Value("${spring.datasource.url}")
    private String url;

    @PostConstruct
    public void initDataSource() {
        // 数据源初始化逻辑同上
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        instance = applicationContext.getBean(ConnectionFactory.class);
    }

    public static Connection getDatabaseConnection() throws SQLException {
        return instance.dataSource.getConnection();
    }
}

方案二:手动读取配置文件(不推荐)

若不想依赖Spring容器管理,可直接读取application.properties文件:

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnection;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;

public class ConnectionFactory {
    private static interface Singleton {
        final ConnectionFactory INSTANCE = new ConnectionFactory();
    }

    private final DataSource dataSource;
    private String user;
    private String password;
    private String url;

    private ConnectionFactory() {
        try {
            // 读取配置文件
            Properties props = PropertiesLoaderUtils.loadProperties(new ClassPathResource("application.properties"));
            this.user = props.getProperty("spring.datasource.username");
            this.password = props.getProperty("spring.datasource.password");
            this.url = props.getProperty("spring.datasource.url");
        } catch (IOException e) {
            throw new RuntimeException("加载application.properties失败", e);
        }

        Properties properties = new Properties();
        properties.setProperty("user", user);
        properties.setProperty("password", password);

        GenericObjectPool<PoolableConnection> pool = new GenericObjectPool<>();
        DriverManagerConnectionFactory connectionFactory = new DriverManagerConnectionFactory(
                url, properties
        );
        new PoolableConnectionFactory(
                connectionFactory, pool, null, "SELECT 1", 3, false, false, Connection.TRANSACTION_READ_COMMITTED
        );

        this.dataSource = new PoolingDataSource(pool);
    }

    public static Connection getDatabaseConnection() throws SQLException {
        return Singleton.INSTANCE.dataSource.getConnection();
    }
}

注意事项

  • 确保ConnectionFactory所在包被Spring扫描到(可通过@ComponentScan指定扫描包)。
  • 配置文件中的键名与代码中@Value的表达式必须完全匹配。

内容的提问来源于stack exchange,提问作者Michel Brito

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 12:40:21