【问题标题】:Spring Batch @Primary annotation overriding incorrect beanSpring Batch @Primary 注释覆盖不正确的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。相反,我得到了这个:

2017-03-09 12:46:21.422 INFO 1496 --- [main] o.s.b.f.s.DefaultListableBeanFactory:用不同的定义覆盖 bean 'dataSource' 的 bean 定义:替换 [Root bean: class [null];范围=;摘要=假;懒惰初始化=假;自动线模式=3;依赖检查=0;自动接线候选=真;主要=假; factoryBeanName=mySQLConfiguration;工厂方法名=数据源;初始化方法名=空; destroyMethodName=(推断);在类路径资源 [config/MySQLConfiguration.class]] 中定义为 [Root bean: class [null];范围=;摘要=假;懒惰初始化=假;自动线模式=3;依赖检查=0;自动接线候选=真;主要=假; factoryBeanName=postgreSQLConfiguration;工厂方法名=数据源;初始化方法名=空; destroyMethodName=(推断);在类路径资源 [config/PostgreSQLConfiguration.class] 中定义

它使用 postgreSQLConfig bean 覆盖 mySQLConfig bean,因此使用 postgresql 驱动程序。问题是,为什么?

【问题讨论】:

    标签: java spring spring-boot spring-batch


    【解决方案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");
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-04-07
      • 2017-02-18
      • 1970-01-01
      • 2011-07-31
      • 1970-01-01
      • 2020-08-07
      • 2019-05-04
      • 2012-02-03
      • 2011-12-08
      相关资源
      最近更新 更多