Spring中不同配置文件绑定不同Bean时属性重复注入问题求解
解决Spring多数据源配置Bean属性注入重复的问题
我最近遇到了一个Spring配置的问题:我有MySQL和Oracle两个数据源的配置文件,分别创建了对应的配置绑定类,但把这两个Bean注入到配置类时,它们的属性居然被注入了相同的值!
先给大家看看我的配置和代码:
我的配置文件
MySQL配置文件 mysql.properties
dialect=org.hibernate.dialect.MySQL57Dialect hbm2ddl_method=validate show_sql=true format_sql=false pool_name=testpool jdbc_url=jdbc:mysql://localhost:3306/testdb minimum_idle=2 uname=root password=testpsw cache_prep_stmts=true prep_stmt_cache_size=256 prep_stmt_cache_sql_limit=2048 use_server_prep_stmts=true maximum_pool_size=30 driver_class_name=com.mysql.jdbc.Driver
Oracle配置文件 oracle.properties
dialect=org.hibernate.dialect.Oracle10gDialect hbm2ddl_method=validate show_sql=true format_sql=false pool_name=testpool jdbc_url=jdbc:oracle:thin:@localhost:1521:testdb minimum_idle=2 uname=barn_act password=testpsw cache_prep_stmts=true prep_stmt_cache_size=256 prep_stmt_cache_sql_limit=2048 use_server_prep_stmts=true maximum_pool_size=30 driver_class_name=oracle.jdbc.OracleDriver
配置绑定类
MySQL配置绑定类
@Component("mysql_props") @PropertySource(value = "classpath:/mysql.properties") @ConfigurationProperties @Getter @Setter public class HibernateMySQLProperties { private String dialect; // 其他对应属性省略 }
Oracle配置绑定类
@Component("oracle_props") @PropertySource(value = "classpath:/oracle.properties") @ConfigurationProperties @Getter @Setter public class HibernateOracleProperties { // 与MySQL类完全相同的字段 }
注入时的问题
当我把这两个Bean注入到PersistenceConfig类时,发现两个Bean的属性值完全一样:
@Configuration @EnableConfigurationProperties({ HibernateOracleProperties.class, HibernateMySQLProperties.class }) public class PersistenceConfig { @Autowired @Qualifier("oracle_props") private HibernateOracleProperties oracleProps; @Autowired @Qualifier("mysql_props") private HibernateMySQLProperties mysqlProps; }
问题根源
其实这个问题很好理解:@ConfigurationProperties默认会绑定没有前缀的属性,而我的两个配置文件里的属性键名完全一致(比如dialect、jdbc_url这些)。Spring加载配置的时候,会把所有无前缀的属性合并,最后后加载的配置会覆盖之前的,导致两个绑定类拿到的都是同一套值。
解决方法
这里给你两种靠谱的解决思路:
方法一:给配置加专属前缀(推荐)
给每个数据源的配置加上独特的前缀,让Spring能区分不同的配置组:
- 修改配置文件,给所有属性加上前缀:
mysql.properties里的属性都加上mysql.前缀,比如mysql.dialect=xxxoracle.properties里的属性都加上oracle.前缀,比如oracle.dialect=xxx
修改后的mysql.properties示例:
mysql.dialect=org.hibernate.dialect.MySQL57Dialect mysql.hbm2ddl_method=validate mysql.show_sql=true # 其他属性同理加上mysql.前缀
- 修改配置绑定类,指定
@ConfigurationProperties的prefix参数:
@Component("mysql_props") @PropertySource(value = "classpath:/mysql.properties") @ConfigurationProperties(prefix = "mysql") // 指定绑定mysql.前缀的属性 @Getter @Setter public class HibernateMySQLProperties { private String dialect; // 其他属性不变 }
@Component("oracle_props") @PropertySource(value = "classpath:/oracle.properties") @ConfigurationProperties(prefix = "oracle") // 指定绑定oracle.前缀的属性 @Getter @Setter public class HibernateOracleProperties { // 字段和MySQL类一致即可 }
这种方法清晰明了,以后扩展其他数据源也很方便,是最推荐的做法。
方法二:调整注解使用方式,避免全局绑定
如果你不想改配置文件的前缀,可以试试这个方法:
- 从
PersistenceConfig中移除@EnableConfigurationProperties注解。因为你已经在绑定类上用了@Component和@PropertySource,这时候@EnableConfigurationProperties会触发全局的无前缀属性绑定,反而造成冲突。
修改后的PersistenceConfig:
@Configuration // 去掉@EnableConfigurationProperties public class PersistenceConfig { @Autowired @Qualifier("oracle_props") private HibernateOracleProperties oracleProps; @Autowired @Qualifier("mysql_props") private HibernateMySQLProperties mysqlProps; }
- 确保你的组件扫描范围包含这两个配置绑定类所在的包,Spring能正确扫描到它们。
这样每个绑定类会单独加载自己的配置文件,@ConfigurationProperties只会绑定当前类对应的属性,不会和其他Bean冲突。
验证方法
修改完成后,你可以在PersistenceConfig里加个初始化方法,打印两个Bean的dialect属性:
@PostConstruct public void checkProps() { System.out.println("MySQL dialect: " + mysqlProps.getDialect()); System.out.println("Oracle dialect: " + oracleProps.getDialect()); }
启动应用后,如果输出分别是MySQL和Oracle对应的方言类,就说明问题解决啦!
内容的提问来源于stack exchange,提问作者Seymur Asadov
相关产品推荐
相关产品推荐

