Я хотел бы создать весенний пакетный проект, в котором пакет не использует мой источник данных

Я видел много примеров проектов Spring Batch, в которых либо (а) источник данных определен, либо (б) источник данных не определен.

Однако в моем проекте мне бы хотелось, чтобы у моей бизнес-логики был доступ к источнику данных, но я хочу, чтобы Spring Batch НЕ использовал источник данных. Это возможно?

У этого парня похожая проблема: Spring boot + spring batch без DataSource

1 ответ

Как правило, использование Spring-Batch без базы данных не является хорошей идеей, поскольку могут возникнуть проблемы с параллелизмом в зависимости от типа задания, которое вы определяете. Поэтому, по крайней мере, настоятельно рекомендуется использовать базу данных inmemory, особенно если вы планируете использовать эту работу на производстве.

Использование SpringBatch с SpringBoot инициализирует источник данных памяти, если вы не конфигурируете свои собственные источники данных.

Принимая это во внимание, позвольте мне переопределить ваш вопрос следующим образом: может ли моя businesslogic использовать другой источник данных, чем Springbatch, для обновления своих BATCH-таблиц? Да, оно может. На самом деле вы можете использовать столько источников данных, сколько захотите, в своих заданиях SpringBatch. Просто используйте автоматическое подключение по имени.

Вот как я это делаю: я всегда использую класс Configuration, который определяет все источники данных, которые я должен использовать в своих работах

Configuration
public class DatasourceConfiguration {

    @Bean
    @ConditionalOnMissingBean(name = "dataSource")
    public DataSource dataSource() {
        // create datasource, that is used by springbatch
        // for instance, create an inmemory datasource using the 
        // EmbeddedDatabaseFactory
        return ...; 
    }

    @Bean
    @ConditionalOnMissingBean(name = "bl1datasource")
    public DataSource bl1datasource() {
        return ...; // your first datasource that is used in your businesslogic
    }

    @Bean
    @ConditionalOnMissingBean(name = "bl2datasource")
    public DataSource bl2datasource() {
        return ...; // your second datasource that is used in your businesslogic
    }
}

Три замечания:

SpringBatch ищет источник данных с именем "dataSource", если вы не укажете это EXACT-имя (в верхнем регистре 'S') в качестве имени, Spring Batch попытается выполнить автоматическое подключение по типу и, если найдет более одного экземпляра DataSource, это бросит исключение.

Поместите свою конфигурацию источника данных в свой собственный класс. Не помещайте их в тот же класс, что и ваши определения работы. Spring должен иметь возможность создавать экземпляр datasource-SpringBean с именем "dataSource" очень рано, когда загружает контекст. До того, как он начнет создавать экземпляры ваших Job- и Step-Beans. Spring не сможет сделать это правильно, если вы поместите определения источника данных в тот же класс, в котором у вас есть определения задания / шага.

Использование @ConditionalOnMissingBean не обязательно, но я нашел это хорошей практикой. Это позволяет легко изменять источники данных для модульных / интеграционных тестов. Просто предоставьте дополнительную конфигурацию теста в ContextConfiguration вашего модульного / ИТ-теста, который, например, перезаписывает "bl1Datasource" с помощью inMemoryDataSource:

Configuration
public class TestBL1DatasourceConfiguration {

    // overwritting bl1datasource with an inMemoryDatasource.
    @Bean
    public DataSource bl1datasource() {
        return new EmbeddedDatabaseFactory.getDatabase(); 
    }
}

Чтобы использовать источники данных businesslogic, используйте инъекцию по имени:

@Component
public class PrepareRe1Re2BezStepCreatorComponent {

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Autowired
    private DataSource bl1datasource;

    @Autowired
    private DataSource bl2datasource;

    public Step createStep() throws Exception {
        SimpleStepBuilder<..., ...> builder =
                stepBuilderFactory.get("astep") //
                .<..., ...> chunk(100) //
                .reader(createReader(bl1datasource)) //
                .writer(createWriter(bl2datasource)); //

        return builder.build();
    }
}

Кроме того, вы, вероятно, захотите использовать источники данных XA, если хотите работать с несколькими источниками данных.

Отредактировано:

Поскольку кажется, что вы действительно не хотите использовать источник данных, вам нужно реализовать свой собственный BatchConfigurer ( http://docs.spring.io/spring-batch/trunk/apidocs/org/springframework/batch/core/configuration/annotation/BatchConfigurer.html) (как указывал Майкл Минелла, руководитель проекта SpringBatch).

Вы можете использовать код org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer в качестве отправной точки для вашей собственной реализации. Просто удалите весь код источника данных / транзакции и сохраните содержимое if (datasource === null) часть в методе инициализации. Это инициализирует MapBasedJobRepository и MapBasedJobExplorer. Но опять же, это НЕ пригодное для использования решение в продуктивной среде, поскольку оно не является поточно-ориентированным.

Отредактировано:

Как это реализовать:

Класс конфигурации, который определяет "businessDataSource":

@Configuration
public class DataSourceConfigurationSimple {
    DataSource embeddedDataSource;

    @Bean
    public DataSource myBusinessDataSource() {
        if (embeddedDataSource == null) {
            EmbeddedDatabaseFactory factory = new EmbeddedDatabaseFactory();
            embeddedDataSource = factory.getDatabase();
        }
        return embeddedDataSource;
    }
}

Реализация определенного BatchConfigurer: (конечно, методы должны быть реализованы...)

public class MyBatchConfigurer implements BatchConfigurer {
    @Override
    public JobRepository getJobRepository() throws Exception {
        return null;
    }

    @Override
    public PlatformTransactionManager getTransactionManager() throws Exception {
        return null;
    }

    @Override
    public JobLauncher getJobLauncher() throws Exception {
        return null;
    }

    @Override
    public JobExplorer getJobExplorer() throws Exception {
        return null;
    }
}

И, наконец, основная конфигурация и класс запуска:

@SpringBootApplication
@Configuration
@EnableBatchProcessing

// Importing MyBatchConfigurer will install your BatchConfigurer instead of
// SpringBatch default  configurer.
@Import({DataSourceConfigurationSimple.class, MyBatchConfigurer.class})

public class SimpleTestJob {

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Bean
    public Job job() throws Exception {
        SimpleJobBuilder standardJob = this.jobs.get(JOB_NAME)
                                                .start(step1());
        return standardJob.build();
    }

    protected Step step1() throws Exception {
        TaskletStepBuilder standardStep1 = this.steps.get("SimpleTest_step1_Step")
                                                     .tasklet(tasklet());
        return standardStep1.build();
    }

    protected Tasklet tasklet() {
        return (contribution, context) -> {
            System.out.println("tasklet called");
            return RepeatStatus.FINISHED;
        };
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(SimpleTestJob.class, args);
    }
}
Другие вопросы по тегам