我想创建一个批处理不使用我的数据源的spring批处理项目 [英] I would like to create a spring batch project where batch does not use my datasource

查看:872
本文介绍了我想创建一个批处理不使用我的数据源的spring批处理项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我见过很多Spring Batch项目的例子,其中(a)定义了一个dataSource,或者(b)没有定义dataSource。

I have seen a lot of examples of Spring Batch projects where either (a) a dataSource is defined, or (b) no dataSource is defined.

但是,在我的项目中,我希望我的业务逻辑可以访问dataSource,但我希望Spring Batch不要使用dataSource。这可能吗?

However, in my project, I would like my business logic to have access to a dataSource, but I want Spring Batch to NOT use the dataSource. Is this possible?

这家伙有类似的问题: Spring boot +没有DataSource的spring批处理

This guy has a similar problem: Spring boot + spring batch without DataSource

推荐答案

一般来说,使用不带数据库的spring-batch不是好主意,因为可能存在并发问题,具体取决于您定义的工作类型。因此,强烈建议至少使用内存数据库,特别是如果您计划在生产中使用该作业。

Generally, using spring-batch without a database is not a good idea, since there could be concurrency issues depending on the kind of job you define. So at least an using an inmemory db is strongly advised, especially if you plan to use the job in production.

将SpringBatch与SpringBoot一起使用将初始化一个内存数据源,如果你不要配置你自己的数据源。

Using SpringBatch with SpringBoot will initialize an inmemory datasource, if you do not configure your own datasource(s).

考虑到这一点,让我按如下方式重新定义你的问题:我的businesslogic可以使用另一个数据源而不是springbatch用来更新它的BATCH表?
是的,它可以。事实上,您可以在SpringBatch Jobs中使用任意数量的数据源。只需使用按名称自动装配。

Taking this into account, let me redefine your question as follows: Can my businesslogic use another datasource than springbatch is using to update its BATCH-tables? Yes, it can. As a matter of fact, you can use as many datasources as you want inside your SpringBatch Jobs. Just use by-name autowiring.

以下是我的工作方式:
我总是使用Configuration类,它定义了我必须使用的所有数据源工作

Here is how I do it: I always use Configuration class, which defines all the datasources I have to use in my Jobs

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批次将尝试按类型自动装配,如果它找到多个DataSource实例,它将抛出异常。

SpringBatch is looking for a datasource with the name "dataSource", if you do not provide this EXACT (uppercase 'S') name as the name, spring batch will try to autowire by type and if it finds more than one instance of DataSource, it will throw an exception.

将您的数据源配置放在自己的类中。不要把它们放在与你的工作定义相同的类中。 Spring需要能够在加载上下文时尽早将名称为dataSource的数据源SpringBean实例化。在它开始实例化你的Job-and-Step-Beans之前。如果将数据源定义放在与作业/步骤定义相同的类中,Spring将无法正确执行。

Put your datasource configuration in its own class. Do not put them in the same class as your jobdefinitions are. Spring needs to be able to instantiate the datasource-SpringBean with the name "dataSource" very early when it loads the context. Before it starts to instantiate your Job- and Step-Beans. Spring will not be able to do it correctly, if you put your datasource definitions in the same class as you have your job/step definitions.

使用@ConditionalOnMissingBean不是必需的,但我发现这是一个很好的实践。它可以轻松更改单元/集成测试的数据源。只需在单元/ IT测试的ContextConfiguration中提供额外的测试配置,例如,用inMemoryDataSource覆盖bl1Datasource:

Using @ConditionalOnMissingBean is not mandatory, but I found it a good practics. It makes it easy to change the datasources for unit/integration tests. Just provide an additional test configuration in the ContextConfiguration of your unit/IT test which, for instance, overwrites the "bl1Datasource" with an inMemoryDataSource:

Configuration
public class TestBL1DatasourceConfiguration {

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

为了使用businesslogic数据源,请使用注入姓名:

In order to use the businesslogic datasources, use injection by name:

@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-Datasources如果您想使用多个数据源。

Furthermore, you probably want to consider using XA-Datasources if you'd like to work with several datasources.

已编辑:

由于您似乎确实不想使用数据源,因此必须实现自己的BatchConfigurer( http://docs.spring.io/spring-batch/trunk/apidocs/org/springframework/batch/core/configuration/annotation/BatchConfigurer .html )(正如Michael Minella-- SpringBatch项目负责人 - 上面指出的那样)。

Since it seems that you really don't want to use a datasource, you have to implement your own BatchConfigurer (http://docs.spring.io/spring-batch/trunk/apidocs/org/springframework/batch/core/configuration/annotation/BatchConfigurer.html) (as Michael Minella - the SpringBatch project lead - pointed out above).

您可以使用org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer的代码作为您自己实现的起点。只需删除所有数据源/事务管理器代码,并在initialize方法中保留 if(datasource === null)部分的内容。这将初始化MapBasedJobRepository和MapBasedJobExplorer。但同样,这在生产环境中不是一个可用的解决方案,因为它不是线程安全的。

You can use the code of org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer as a starting point for your own implementation. Simply remove all the datasource/transactionmanager code and keep the content of the if (datasource === null) part in the initialize method. This will initialize a MapBasedJobRepository and MapBasedJobExplorer. But again, this is NOT a useable solution in a productive environment, since it is not threadsafe.

已编辑:

如何实现它:

定义businessDataSource的配置类:

Configuration class that defines the "businessDataSource":

@Configuration
public class DataSourceConfigurationSimple {
    DataSource embeddedDataSource;

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

特定BatchConfigurer的实现:
(当然,必须实现这些方法......)

The implementation of a specific BatchConfigurer: (of course, the methods have to be implemented...)

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;
    }
}

最后是主配置和启动类:

And finally the main configuration and launch class:

@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);
    }
}

这篇关于我想创建一个批处理不使用我的数据源的spring批处理项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆