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
相关产品推荐
相关产品推荐

