Создать @JobScope @Service с помощью Spring Batch, который содержит общую память для задания? - PullRequest
0 голосов
/ 08 мая 2020

По сути, я хочу создать @Service или компонент, который загружает некоторые данные в память из таблицы базы данных, на которую ссылаются во время выполнения задания

package com.squareup.se.bridge.batchworker.components.context;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;
import com.squareup.se.bridge.batchworker.repositories.BridgeBatchJobParametersRepository;
import com.squareup.se.bridge.batchworker.util.JobParameterKeys;
import com.squareup.se.bridge.core.api.services.batchworker.FatalSyncException;
import com.squareup.se.bridge.core.integration.util.logger.JobExecutionLoggerFactory;
import java.io.IOException;
import javax.validation.constraints.NotNull;
import org.slf4j.Logger;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.stereotype.Component;

@JobScope @Component public class BridgeBatchIntegrationJobContextProvider
    implements JobExecutionListener {
  private Logger logger;
  private ObjectMapper mapper;
  private BridgeBatchJobParametersRepository bridgeBatchJobParametersRepository;
  private BridgeIntegrationJobContext context;

  public BridgeBatchIntegrationJobContextProvider(ObjectMapper mapper,
      BridgeBatchJobParametersRepository bridgeBatchJobParametersRepository) {
    this.mapper = mapper;
    this.bridgeBatchJobParametersRepository = bridgeBatchJobParametersRepository;
  }

  @Override public void beforeJob(JobExecution jobExecution) {
    var jobId = jobExecution.getJobParameters().getString(JobParameterKeys.SYNC_ID);
    this.logger = JobExecutionLoggerFactory.getLogger(
        BridgeBatchIntegrationJobContextProvider.class, jobId);
    this.context = deserializeJobParameters(jobId);
  }

  @NotNull public BridgeIntegrationJobContext get() {
    if (context == null) {
      throw new IllegalStateException("Expected context to exist before calling this method");
    }
    return context;
  }

  @Override public void afterJob(JobExecution jobExecution) { }

  @NotNull private String getParameters(String jobId) {
    var jobParams = bridgeBatchJobParametersRepository.find(jobId);
    if (jobParams == null || jobParams.size() == 0) {
      throw new FatalSyncException(String.format("No job parameters for job `%s` exists", jobId));
    }
    if (jobParams.size() > 1) {
      throw new FatalSyncException(String.format("Multiple parameter entries exist for job `%s`",
          jobId));
    } else if (Strings.isNullOrEmpty(jobParams.get(0).getIntegrationContext())) {
      throw new FatalSyncException(String.format("Job parameters for job `%s` is empty", jobId));
    }
    return jobParams.get(0).getIntegrationContext();
  }

  @NotNull private BridgeIntegrationJobContext deserializeJobParameters(String jobId) {
    try {
      return mapper.readValue(getParameters(jobId),
          BridgeIntegrationJobContext.class);
    } catch (IOException e) {
      //TODO page on this
      logger.info(e.getMessage(), e);
      throw new FatalSyncException(e);
    }
  }
}

Я настроил задание вот так:

return jobBuilderFactory.get(CUSTOMERS_BATCH_JOB_NAME)
        .incrementer(new RunIdIncrementer())
        .start(loadFromOriginStep)
        .next(retryFailuresFromOriginStep)
        .listener(bridgeBatchIntegrationJobContextProvider)
        .listener(jobListener)
        .build();

Конструктор зависит от других bean-компонентов, включая сопоставитель объектов Jackson и репозиторий JPA. Я столкнулся с несколькими проблемами:

  1. конструктор не создается Spring, и поэтому переменные экземпляра, которые я хочу связать, отсутствуют

Если я удалю @JobScope из компонента Spring создает экземпляр компонента.

1 Ответ

0 голосов
/ 11 мая 2020

Я не вижу, где @JobContext используется в вашем коде, и, согласно вашим требованиям, он вам не нужен.

Если вы хотите загрузить некоторые данные в контексте выполнения задания с помощью прослушивателя, вы можете сделать это в beforeJob с помощью jobExecution.getExecutionContext().put("key", "value");.

Тем не менее, загружать не рекомендуется много данных в контексте выполнения, поскольку они сохраняются между шагами.

Итак, если вы не загружаете небольшой объем данных в контексте выполнения, вам нужно найти другой подход (например, использование отдельного кеша, например см. Пакет Spring с аннотациями и кешированием ).

...