Spring Batch @Primary 注释覆盖不正确的bean
Posted
技术标签:
【中文标题】Spring Batch @Primary 注释覆盖不正确的bean【英文标题】:Spring Batch @Primary annotation overriding incorrect bean 【发布时间】:2017-07-30 07:43:30 【问题描述】:我跟着this tutorial 用Java 配置了一个Spring Batch 作业。它通过使用由每个数据源实现的接口来提供多个数据源。
这是我目前所拥有的:
InfrastructureConfig.java
public interface InfrastructureConfiguration
@Bean
DataSource dataSource();
MySQLConfig.java
@Configuration
@Primary
public class mysqlConfiguration implements InfrastructureConfiguration
@Bean
public DataSource dataSource()
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/employees?useSSL=false");
dataSource.setUsername("testing");
dataSource.setPassword("testing");
return dataSource;
PostgreSQLConfig.java
@Configuration
public class PostgreSQLConfiguration implements InfrastructureConfiguration
@Bean
public DataSource dataSource()
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://localhost:5432/postgres");
dataSource.setUsername("postgres");
dataSource.setPassword("testing");
return dataSource;
JobConfig.java
@Configuration
public class JobConfig
@Autowired
private InfrastructureConfig infrastructureConfig
....
通过对我的 MySQLConfig 使用 @Primary
注释,我希望使用 mySQLConfig bean。相反,我得到了这个:
它使用 postgreSQLConfig bean 覆盖 mySQLConfig bean,因此使用 postgresql 驱动程序。问题是,为什么?
【问题讨论】:
【参考方案1】:将@Primary
放在方法上(@Bean
旁边)而不是类级别。
【讨论】:
如果我这样做,我会收到一条错误消息,指出“Field InfrastructureConfig 需要一个 bean,但找到了 2 个:mySQLConfiguration 和 postgreSQLConfiguration”【参考方案2】:尝试使用@Qualifier(name = "")
然后明确选择您想要的实例。
您在接口方法上有@Bean
注释也很奇怪。
此外,使用自动装配 @Configuration 类对我来说也是一种不好的做法。它们是用于实例化 bean 的基于 java 的配置。
【讨论】:
我试过@Qualifier("mySQLConfig")
和@Resource(name="mySQLConfig")
都没有运气。至于其余的,我只是按照上面链接的 Spring Batch 教程中指定的内容进行操作。那么,该教程肯定存在根本性错误。但是去掉接口方法上的@Bean
注解并没有什么不同,用@Inject
注解代替@Autowire
也是徒劳的。
嗯。从所有方法中删除 @Bean 注释。实际上将子配置上的@Configuration
更改为@Component
。我猜你已经启用了组件扫描,对吧?我还看到名称不匹配 - InfrastructureConfig 和 InfrastructureConfiguration 。会不会是问题?
名称不匹配只是我在评论中的错误,对不起。我已经尝试了您的建议,但仍然没有运气。这是一个更复杂系统的一小部分,我认为问题可能出在其他地方。找到答案后,我会更新答案(希望很快)
这行为正确,请参阅错误jira.spring.io/browse/SPR-13980 "@Primary 对这种按名称覆盖的行为没有影响,因为它仅适用于注入点解析:即当多个在 bean 定义注册表中找到了匹配的 bean,但是对于特定的注入点只选择一个。这在概念上与重写 bean 定义非常不同,后者导致在注册表中硬替换,以前注册的 bean 不再可用。 "
关于 Spring bean 的唯一 ID 的有趣阅读。 intertech.com/Blog/clarifying-spring-framework-ids-and-names 这不是使用@Primary 注解的答案,而是阐明了在创建具有相同标识的多个bean 时Spring 的行为方式。【参考方案3】:
你可以试试@Profiles
注解。
用@Profile("mySql")
注释mySql配置类,用@Profile("myPostgresql")
注释Postgres配置
然后用@ActiveProfiles("mySql")
注释JobConfig
配置。这样JobConfig
应该会忽略 postgres 配置。
假设你在测试中使用 MySQL,你可以用 @ActiveProfiles("mySql")
注释测试类
Spring Profiles documentation
文档中的示例:
@Configuration
public class AppConfig
@Bean("dataSource")
@Profile("development")
public DataSource standaloneDataSource()
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
@Bean("dataSource")
@Profile("production")
public DataSource jndiDataSource() throws Exception
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
【讨论】:
以上是关于Spring Batch @Primary 注释覆盖不正确的bean的主要内容,如果未能解决你的问题,请参考以下文章
@Primary 等效于自动装配的 Spring JPA 存储库
Spring IOC容器注解 @Autowired@Resource@Primary@Value的用法
Spring Batch 无法通过 DB (postgres) 获取作业锁
如何评估在应用程序中是使用spring batch还是scheduler?
spring batch(二):核心部分:配置Spring batch
带有单个数据源的 SpringBoot + Batch + Cloud Task @EnableTask 注释导致“序列不存在”问题