【问题标题】:How to pass a String (Non managed bean) to a managed bean如何将字符串(非托管 bean)传递给托管 bean
【发布时间】:2018-12-24 05:41:27
【问题描述】:

我有一份春季批处理作业。有一个步骤正在调用 reader 方法。

步骤

@Bean public Step myStep(FlatFileItemWriter<String> writer, Processor
processor,  @Value("${com.tableName}") String myTableName) {
    return stepBuilderFactory.get("step1")
        .<MyBean, String> chunk(this.chuckSize)
        .reader(reader(myTableName, this.myRowMapper))
        .processor(processor)
        .writer(writer)
        .build(); 
}

读者 工作

@Bean
public <T> JdbcCursorItemReader<T> reader(@Value("${com.tableName}") String tableName, RowMapper<T> rowMapper) {
    JdbcCursorItemReader<T> jdbcCursorItemReader = new JdbcCursorItemReader<>();
    String query = "select * from " + tableName;
    jdbcCursorItemReader.setDataSource(dataSource);
    jdbcCursorItemReader.setSql(query);
    jdbcCursorItemReader.setRowMapper(rowMapper);

    return jdbcCursorItemReader;
}

我希望我的读者采用动态表名。所以我将阅读器更改为如下所述。

@Bean
public <T> JdbcCursorItemReader<T> reader(String tableName, RowMapper<T> rowMapper) {
    JdbcCursorItemReader<T> jdbcCursorItemReader = new JdbcCursorItemReader<>();
    String query = "select * from " + tableName;
    jdbcCursorItemReader.setDataSource(dataSource);
    jdbcCursorItemReader.setSql(query);
    jdbcCursorItemReader.setRowMapper(rowMapper);

    return jdbcCursorItemReader;
}

这会导致以下错误。

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method reader in com.walgreens.oracleextractionbatch.OracleExtractionJobConfiguration required a bean of type 'java.lang.String' that could not be found.


Action:

Consider defining a bean of type 'java.lang.String' in your configuration.

在激烈的谷歌搜索之后,我尝试了很多解决方法。但我认为我缺少一些基本的东西。请帮忙。 TIA

【问题讨论】:

  • 您是否尝试使用原型范围定义阅读器 bean?默认情况下,它是单例范围,并且由于没有有关 tableName 的信息,因此您会收到错误消息。您正在寻找不同表名的读取器 bean,即每个表名一个 bean。尝试使用@scope("prototype") 或@scope(BeanDefinition.SCOPE_PROTOTYPE) 对阅读器进行注释,看看是否有效。
  • @Akash,我认为这应该可以解决问题。我会尽力让你知道...
  • 对你的情况有用吗?

标签: spring spring-batch spring-ioc


【解决方案1】:

我将 ReaderWriterStep bean 的范围更改为 prototype。我将处理器 bean 的范围保持原样(单例),因为处理器逻辑对于所有场景都是相同的。

谢谢,阿卡什

【讨论】:

    【解决方案2】:

    在 Spring 批处理的上下文中使 Reader 动态化会使它们变得懒惰。

    我们可以使用@StepScope 让读者和作家变得懒惰。现在有了 StepScope,我们就可以传递参数了。最流行的参数传递方式是使用JobParametersstepExecutionContext

    在您的情况下,如果您在工作开始时知道表名,请使用JobParameters

    用于在步骤中访问JobParameters 的示例代码。

     @Bean
            @StepScope
            public <T> JdbcCursorItemReader<T> reader(@Value("#{jobParameters['tableName']}") String tableName), RowMapper<T> rowMapper) {
    

    如果您从某些处理中获取表名(在之前的某个步骤中),那么您需要在stepExecutionContext 中设置表名

    这是您可以从stepExecutionContext 访问表名的方式

     @Bean
        @StepScope
        public <T> JdbcCursorItemReader<T> reader(@Value("#{stepExecutionContext['tableName']}") String tableName), RowMapper<T> rowMapper) {
            JdbcCursorItemReader<T> jdbcCursorItemReader = new JdbcCursorItemReader<>();
            String query = "select * from " + tableName;
            jdbcCursorItemReader.setDataSource(dataSource);
            jdbcCursorItemReader.setSql(query);
            jdbcCursorItemReader.setRowMapper(rowMapper);
    
            return jdbcCursorItemReader;
        }   
    

    希望对你有帮助

    【讨论】:

    • 感谢您的回复。但是在我们从 stepExecutionContext 获取值之前,我们不应该设置它。我没有在 Step 执行上下文中设置任何内容。
    • @Andy 更新了答案,提供了更多细节,希望对您有所帮助
    • 我面临的问题不是传递表名参数的值,而是创建具有不同查询的多个读取器[这就是不同表名的原因],以便我可以对这些表执行读取操作。我使用原型范围修复了这个问题。
    猜你喜欢
    • 2015-12-02
    • 2013-03-06
    • 1970-01-01
    • 1970-01-01
    • 2016-12-26
    • 1970-01-01
    • 2016-07-09
    • 2012-01-17
    • 2017-02-07
    相关资源
    最近更新 更多