web-dev-qa-db-fra.com

Spring-Batch sans métadonnées persistantes dans la base de données?

Je veux créer un spring-batch job, mais je veux l'exécuter sans aucune persistance de base de données. Malheureusement, Spring-batch nécessite d'écrire metadata ob les cycles de travail dans une base de données, me procurant ainsi au moins une sorte de base de données avec transactionmanager et entitymanager.

Est-il possible d'empêcher les métadonnées et de fonctionner indépendamment des txmanagers et des bases de données?

Mise à jour:

ERROR org.springframework.batch.core.job.AbstractJob: Encountered fatal error executing job
Java.lang.NullPointerException
    at org.springframework.batch.core.repository.dao.MapJobExecutionDao.synchronizeStatus(MapJobExecutionDao.Java:158) ~[spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
    at org.springframework.batch.core.repository.support.SimpleJobRepository.update(SimpleJobRepository.Java:161) ~[spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
    at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.7.0_51]
    at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57) ~[?:1.7.0_51]
    at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43) ~[?:1.7.0_51]
    at Java.lang.reflect.Method.invoke(Method.Java:606) ~[?:1.7.0_51]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.Java:317) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.Java:190) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:157) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.Java:98) ~[spring-tx-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.Java:262) ~[spring-tx-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.Java:95) ~[spring-tx-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:207) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at com.Sun.proxy.$Proxy134.update(Unknown Source) ~[?:?]
    at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.7.0_51]
    at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57) ~[?:1.7.0_51]
    at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43) ~[?:1.7.0_51]
    at Java.lang.reflect.Method.invoke(Method.Java:606) ~[?:1.7.0_51]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.Java:317) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.Java:190) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:157) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.Java:127) ~[spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:207) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at com.Sun.proxy.$Proxy134.update(Unknown Source) ~[?:?]
    at org.springframework.batch.core.job.AbstractJob.updateStatus(AbstractJob.Java:416) ~[spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.Java:299) [spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.Java:135) [spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.Java:50) [spring-core-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.Java:128) [spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
    at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.7.0_51]
    at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57) ~[?:1.7.0_51]
    at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43) ~[?:1.7.0_51]
    at Java.lang.reflect.Method.invoke(Method.Java:606) ~[?:1.7.0_51]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.Java:317) [spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.Java:190) [spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:157) [spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.Java:127) [spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179) [spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:207) [spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
    at com.Sun.proxy.$Proxy50.run(Unknown Source) [?:?]
37
membersound

Je suis revenu à ma propre question, car la solution ne fonctionnait plus. Au printemps-lot-1.5.3, utiliser comme suit:

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
...
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new ResourcelessTransactionManager();
    }
}
9
membersound

Créez simplement une configuration sans source de données pour la configuration par lots:

@Configuration
@EnableAutoConfiguration
@EnableBatchProcessing
public class BatchConfiguration extends DefaultBatchConfigurer {

    @Override
    public void setDataSource(DataSource dataSource) {
        // override to do not set datasource even if a datasource exist.
        // initialize will use a Map based JobRepository (instead of database)
    }

}

Il initialisera JobRepository et JobExplorer avec une implémentation basée sur une carte en mémoire. https://github.com/spring-projects/spring-batch/blob/342d27bc1ed83312bdcd9c0cb30510f4c469e47d/spring-batch-core/src/main/Java/org/springframework/batch/core/configuration/annfigurationBannière. Java # L84

et vous pouvez également utiliser votre source de données de production même si elle est configurée automatiquement avec Spring Boot.

31
Aure77

Je veux l'exécuter sans aucune persistance de base de données

Vous pouvez utiliser MapJobRepositoryFactoryBean et ResourcelessTransactionManager

exemple de configuration:

<bean id="transactionManager"
    class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />

<bean id="jobRepository"
    class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
    <property name="transactionManager" ref="transactionManager" />
</bean>

<bean id="jobLauncher"
    class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
    <property name="jobRepository" ref="jobRepository" />
</bean>

Pour Spring 4.X, la configuration basée sur les annotations serait la suivante:

@Bean
public PlatformTransactionManager getTransactionManager() {
    return new ResourcelessTransactionManager();
}

@Bean
public JobRepository getJobRepo() {
    return new MapJobRepositoryFactoryBean(getTransactionManager()).getObject();
}
25
Braj

Après avoir peaufiné la réponse de @ Braj, ma configuration de travail se présente comme suit:

@Bean
public ResourcelessTransactionManager transactionManager() {
    return new ResourcelessTransactionManager();
}

@Bean
public JobRepository jobRepository(ResourcelessTransactionManager transactionManager) throws Exception {
    MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean = new MapJobRepositoryFactoryBean(transactionManager);
    mapJobRepositoryFactoryBean.setTransactionManager(transactionManager);
    return mapJobRepositoryFactoryBean.getObject();
}

@Bean
public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
    SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
    simpleJobLauncher.setJobRepository(jobRepository);
    return simpleJobLauncher;
}
15
Cleankod

Si vous ne souhaitez pas stocker les métadonnées du travail dans la base de données, la configuration se présente comme suit

@Configuration
public class InMemoryJobRepositoryConfiguration {
@Bean
public ResourcelessTransactionManager transactionManager() {
    return new ResourcelessTransactionManager();
}

@Bean
public MapJobRepositoryFactoryBean mapJobRepositoryFactory(ResourcelessTransactionManager transactionManager)
        throws Exception {
    MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean(transactionManager);
    factory.afterPropertiesSet();
    return factory;
}

@Bean
public JobRepository jobRepository(MapJobRepositoryFactoryBean repositoryFactory) throws Exception {
    return repositoryFactory.getObject();
}

@Bean
public JobExplorer jobExplorer(MapJobRepositoryFactoryBean repositoryFactory) {
    return new SimpleJobExplorer(repositoryFactory.getJobInstanceDao(), repositoryFactory.getJobExecutionDao(),
            repositoryFactory.getStepExecutionDao(), repositoryFactory.getExecutionContextDao());
}

@Bean
public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
    SimpleJobLauncher launcher = new SimpleJobLauncher();
    launcher.setJobRepository(jobRepository);
    return launcher;
}
}

Si le travail doit lire/écrire des données commerciales dans la base de données et que la source de données est configurée comme suit.

@Autowired
private DataSource dataSource;

spring batch crée un schéma interne (tables et séquences BATCH_ *) à l'aide de cette source de données. Pour éviter que cela ne se produise, définissez l'indicateur spring.batch.initializer.enabled=false dans application.properties.

6
MKaz

En plus de la réponse de @ Braj, j'ai dû exclure l'autoconfiguration par lots: @SpringBootApplication(exclude = {BatchAutoConfiguration.class})

Cela ne fonctionnait pas autrement. Cela inclut l'application Spring Boot

5
gmode

J'ai essayé toutes les solutions ci-dessus, mais cela ne fonctionne pas avec mon scénario particulier car mon travail par lots de printemps a des fonctionnalités avancées telles que le multi-threading. Il a besoin d'une base de données. Voici donc ce que j'ai fait pour résoudre le problème:

@Configuration
public class FakeBatchConfig implements BatchConfigurer {

  PlatformTransactionManager transactionManager;
  JobRepository jobRepository;
  JobLauncher jobLauncher;
  JobExplorer jobExplorer;

  @Override
  public JobRepository getJobRepository() {
    return jobRepository;
  }

  @Override
  public PlatformTransactionManager getTransactionManager() {
    return transactionManager;
  }

  @Override
  public JobLauncher getJobLauncher() {
    return jobLauncher;
  }

  @Override
  public JobExplorer getJobExplorer() {
    return jobExplorer;
  }

  @PostConstruct
  void initialize() throws Exception {

    if (this.transactionManager == null) {
      this.transactionManager = new ResourcelessTransactionManager();
    }

    MapJobRepositoryFactoryBean jobRepositoryFactory = new MapJobRepositoryFactoryBean(this.transactionManager);
    jobRepositoryFactory.afterPropertiesSet();
    this.jobRepository = jobRepositoryFactory.getObject();

    MapJobExplorerFactoryBean jobExplorerFactory = new MapJobExplorerFactoryBean(jobRepositoryFactory);
    jobExplorerFactory.afterPropertiesSet();
    this.jobExplorer = jobExplorerFactory.getObject();
    this.jobLauncher = createJobLauncher();
  }

  private JobLauncher createJobLauncher() throws Exception {
    SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
    jobLauncher.setJobRepository(jobRepository);
    jobLauncher.afterPropertiesSet();
    return jobLauncher;
  }

}
5
Qing Xia

Après avoir lu toutes les réponses fournies, je l'ai fait fonctionner. J'ai utilisé un mélange de membres et de solution Aure77. J'ai découvert qu'il n'était pas nécessaire de remplacer la méthode setDataSource. DefaultBatchConfigurer prend automatiquement en charge PlatformTransactionManager et DataSource n'est pas requis. Veuillez noter que j'utilise Spring boot 2.0.3.RELEASE. Voici la méthode que j'ai utilisée

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@EnableBatchProcessing
public class DemoApplication extends DefaultBatchConfigurer {

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Bean
    protected Tasklet tasklet() {

        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution contribution, ChunkContext context) {
                return RepeatStatus.FINISHED;
            }
        };
    }

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

    @Bean
    protected Step step1() throws Exception {
        return this.steps.get("step1").tasklet(tasklet()).build();
    }

    public static void main(String[] args) throws Exception {
        //System.exit(SpringApplication.exit(SpringApplication.run(DemoApplication.class, args)));
        SpringApplication.run(DemoApplication.class, args);
    }
}
2
Akhil Khandelwal

Le plus simple de tous est d'ajouter une base de données intégrée à classpath. Naturellement, la production n'est pas recommandée, mais si vous l'utilisez pour apprendre, gagnez du temps.

Ajoutez à votre pom.xml la dépendance de la base de données H2 intégrée:

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

C'est tout.

1
bl4ckr0se