繁体   English   中英

Spring Batch分区处理程序错误

[英]Spring Batch Partition Handler error

我是Spring框架和Spring Batch的新手

我正在尝试安装示例Spring Batch远程分区示例。

我正在使用此堆栈Spring Boot + Spring Batch + Spring Integration + AWS SQS

遵循以下步骤,我已成功完成。

1.创建所有配置,包括通道,作业,队列和其他内容。

2.Ran主进程,我能够对Table进行分区并将分区元数据推送到AWS SQS。

但是在运行从属进程时,我得到了错误;在从属进程中,我能够从队列中拉出消息,但是在StepExecutionRequestHandler的handle()方法中得到了错误

org.springframework.messaging.MessageHandlingException:嵌套异常是org.springframework.expression.spel.SpelEvaluationException:EL1004E:方法调用:在org.springframework.batch.integration.partition.StepExecutionRequestHandler上找不到方法句柄(java.lang.String)类型,failedMessage = GenericMessage,[payload = StepExecutionRequest:[jobExecutionId = 2,stepExecutionId = 3,stepName = slaveStep],标头= {sequenceNumber = 2,aws_messageId =“”,SentTimestamp = 1523215624042,sequenceSize = 4,SenderId =“”,aws_receiptHand =“”,roximateReceiveCount = 2,correlationId = 2:slaveStep,id =“”,lookupDestination = master,aws_queue = master,roximateFirstReceiveTimestamp = 1523215634470,timestamp = 1523215864910}]]

@Configuration
public class JobConfiguration implements ApplicationContextAware
{

  @Autowired
  public JobBuilderFactory jobBuilderFactory;

  @Autowired
  public StepBuilderFactory stepBuilderFactory;

  @Autowired
  public DataSource dataSource;

  @Autowired
  public JobExplorer jobExplorer;

  @Autowired
  public JobRepository jobRepository;

  private ApplicationContext applicationContext;

  private static final int GRID_SIZE = 4;

  @Bean
  public PartitionHandler partitionHandler(MessagingTemplate messagingTemplate) throws Exception
  {
    MessageChannelPartitionHandler partitionHandler = new MessageChannelPartitionHandler();
    partitionHandler.setStepName("slaveStep");
    partitionHandler.setGridSize(GRID_SIZE);
    partitionHandler.setMessagingOperations(messagingTemplate);
    partitionHandler.setPollInterval(5000l);
    partitionHandler.setJobExplorer(this.jobExplorer);

    partitionHandler.afterPropertiesSet();

    return partitionHandler;
  }

  @Bean
  public ColumnRangePartitioner partitioner()
  {
    ColumnRangePartitioner columnRangePartitioner = new ColumnRangePartitioner();

    columnRangePartitioner.setColumn("id");
    columnRangePartitioner.setDataSource(this.dataSource);
    columnRangePartitioner.setTable("customer");
    return columnRangePartitioner;
  }

  @Bean
  @Profile("slave")
  @ServiceActivator(inputChannel = "inboundRequests", outputChannel = "outboundStaging")
  public StepExecutionRequestHandler stepExecutionRequestHandler()
  {
    StepExecutionRequestHandler stepExecutionRequestHandler = new StepExecutionRequestHandler();

    BeanFactoryStepLocator stepLocator = new BeanFactoryStepLocator();
    stepLocator.setBeanFactory(this.applicationContext);
    stepExecutionRequestHandler.setStepLocator(stepLocator);
    stepExecutionRequestHandler.setJobExplorer(this.jobExplorer);

    return stepExecutionRequestHandler;
  }

  @Bean(name = PollerMetadata.DEFAULT_POLLER)
  public PollerMetadata defaultPoller()
  {
    PollerMetadata pollerMetadata = new PollerMetadata();
    pollerMetadata.setTrigger(new PeriodicTrigger(10));
    return pollerMetadata;
  }

  @Bean
  @StepScope
  public JdbcPagingItemReader<Customer> pagingItemReader(@Value("#{stepExecutionContext['minValue']}") Long minValue,
      @Value("#{stepExecutionContext['maxValue']}") Long maxValue)
  {
    System.out.println("reading " + minValue + " to " + maxValue);
    JdbcPagingItemReader<Customer> reader = new JdbcPagingItemReader<>();

    reader.setDataSource(this.dataSource);
    reader.setFetchSize(100);
    reader.setRowMapper(new CustomerRowMapper());

    MySqlPagingQueryProvider queryProvider = new MySqlPagingQueryProvider();
    queryProvider.setSelectClause("id, firstName, lastName, birthdate");
    queryProvider.setFromClause("from customer");
    queryProvider.setWhereClause("where id >= " + minValue + " and id <= " + maxValue);

    Map<String, Order> sortKeys = new HashMap<>(1);

    sortKeys.put("id", Order.ASCENDING);

    queryProvider.setSortKeys(sortKeys);

    reader.setQueryProvider(queryProvider);

    return reader;
  }

  @Bean
  @StepScope
  public JdbcBatchItemWriter<Customer> customerItemWriter()
  {
    JdbcBatchItemWriter<Customer> itemWriter = new JdbcBatchItemWriter<>();

    itemWriter.setDataSource(this.dataSource);
    itemWriter.setSql("INSERT INTO new_customer VALUES (:id, :firstName, :lastName, :birthdate)");
    itemWriter.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider());
    itemWriter.afterPropertiesSet();

    return itemWriter;
  }

  @Bean
  public Step step1() throws Exception
  {
    return stepBuilderFactory.get("step1").partitioner(slaveStep().getName(), partitioner()).step(slaveStep())
        .partitionHandler(partitionHandler(null)).build();
  }

  @Bean
  public Step slaveStep()
  {
    return stepBuilderFactory.get("slaveStep").<Customer, Customer>chunk(1000).reader(pagingItemReader(null, null)).writer(customerItemWriter())
        .build();
  }

  @Bean
  @Profile("master")
  public Job job() throws Exception
  {
    return jobBuilderFactory.get("job").start(step1()).build();
  }

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
  {
    this.applicationContext = applicationContext;
  }
}

@Configuration
public class IntegrationConfiguration
{

  @Autowired
  private AmazonSQSAsync amazonSqs;

  @Bean
  public MessagingTemplate messageTemplate()
  {
    MessagingTemplate messagingTemplate = new MessagingTemplate(outboundRequests());

    messagingTemplate.setReceiveTimeout(60000000l);

    return messagingTemplate;
  }

  @Bean
  public DirectChannel outboundRequests()
  {
    return new DirectChannel();
  }


  @Bean
  @Profile("slave")
  public MessageProducer sqsMessageDrivenChannelAdapter()
  {
    SqsMessageDrivenChannelAdapter adapter = new SqsMessageDrivenChannelAdapter(this.amazonSqs, "master");
    adapter.setOutputChannel(inboundRequests());
    adapter.afterPropertiesSet();
    return adapter;
  }

  @Bean
  @ServiceActivator(inputChannel = "outboundRequests")
  public MessageHandler sqsMessageHandler()
  {
    SqsMessageHandler messageHandler = new SqsMessageHandler(amazonSqs);
    messageHandler.setQueue("master");
    return messageHandler;
  }

  @Bean
  public PollableChannel outboundStaging()
  {
    return new NullChannel();
  }

  @Bean
  public QueueChannel inboundRequests()
  {
    return new QueueChannel();
  }
}

谢谢

您应该记住, StepExecutionRequestHandler的合同如下:

public StepExecution handle(StepExecutionRequest request)

根据您的例外情况和SQS的性质, inboundRequests消息的有效负载是一个字符串。 而且我相信它在JSON中。 因此,请考虑在JsonToObjectTrabsformer之前使用StepExecutionRequestHandler

更新

有效负载不是JSON格式。 它是一个字符串,是从StepExecutionRequest类的toString()创建的。 格式为StepExecutionRequest: [jobExecutionId=2, stepExecutionId=3,stepName=slaveStep]

好! 我明白你的意思了。 SQS Message只能具有String主体。 默认情况下,用于向SQS发送消息的SqsMessageHandler使用GenericMessageConverter将传入的对象转换为String。

我想你需要考虑配置SqsMessageHandlerMappingJackson2MessageConverter真正序列化StepExecutionRequest到正确的JSON,让它在SQS转移。

在调用之前,其他(从)侧StepExecutionRequestHandler你真的应该放置@Transformer刚过SqsMessageDrivenChannelAdapterJsonToObjectTransformer

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM