Make JobOperator extend JobLauncher

Related to #4832
This commit is contained in:
Mahmoud Ben Hassine
2025-05-07 22:03:03 +02:00
parent adffc588b6
commit fc4a66516a
19 changed files with 105 additions and 179 deletions

View File

@@ -52,8 +52,6 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
private static final String JOB_REPOSITORY = "jobRepository";
private static final String JOB_LAUNCHER = "jobLauncher";
private static final String JOB_REGISTRY = "jobRegistry";
private static final String JOB_LOADER = "jobLoader";
@@ -67,7 +65,6 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
.get(EnableBatchProcessing.class)
.synthesize();
registerJobRepository(registry, batchAnnotation);
registerJobLauncher(registry, batchAnnotation);
registerJobRegistry(registry);
registerJobRegistrySmartInitializingSingleton(registry);
registerJobOperator(registry, batchAnnotation);
@@ -147,25 +144,6 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
registry.registerBeanDefinition(JOB_REPOSITORY, beanDefinitionBuilder.getBeanDefinition());
}
private void registerJobLauncher(BeanDefinitionRegistry registry, EnableBatchProcessing batchAnnotation) {
if (registry.containsBeanDefinition(JOB_LAUNCHER)) {
LOGGER.info("Bean jobLauncher already defined in the application context, skipping"
+ " the registration of a jobLauncher");
return;
}
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition(TaskExecutorJobLauncher.class);
// set mandatory properties
beanDefinitionBuilder.addPropertyReference(JOB_REPOSITORY, JOB_REPOSITORY);
// set optional properties
String taskExecutorRef = batchAnnotation.taskExecutorRef();
if (registry.containsBeanDefinition(taskExecutorRef)) {
beanDefinitionBuilder.addPropertyReference("taskExecutor", taskExecutorRef);
}
registry.registerBeanDefinition(JOB_LAUNCHER, beanDefinitionBuilder.getBeanDefinition());
}
private void registerJobRegistry(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(JOB_REGISTRY)) {
LOGGER.info("Bean jobRegistry already defined in the application context, skipping"
@@ -205,7 +183,6 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
beanDefinitionBuilder.addPropertyReference("transactionManager", transactionManagerRef);
beanDefinitionBuilder.addPropertyReference(JOB_REPOSITORY, JOB_REPOSITORY);
beanDefinitionBuilder.addPropertyReference(JOB_LAUNCHER, JOB_LAUNCHER);
beanDefinitionBuilder.addPropertyReference(JOB_REGISTRY, JOB_REGISTRY);
// set optional properties

View File

@@ -39,7 +39,6 @@ import org.springframework.batch.core.converter.StringToLocalTimeConverter;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.launch.support.JobOperatorFactoryBean;
import org.springframework.batch.core.launch.support.TaskExecutorJobLauncher;
import org.springframework.batch.core.repository.ExecutionContextSerializer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.dao.AbstractJdbcBatchMetadataDao;
@@ -145,27 +144,6 @@ public class DefaultBatchConfiguration implements ApplicationContextAware {
}
}
/**
* Define a job launcher bean.
* @param jobRepository the job repository
* @return a job launcher
* @throws BatchConfigurationException if unable to configure the default job launcher
* @since 5.2
*/
@Bean
public JobLauncher jobLauncher(JobRepository jobRepository) throws BatchConfigurationException {
TaskExecutorJobLauncher taskExecutorJobLauncher = new TaskExecutorJobLauncher();
taskExecutorJobLauncher.setJobRepository(jobRepository);
taskExecutorJobLauncher.setTaskExecutor(getTaskExecutor());
try {
taskExecutorJobLauncher.afterPropertiesSet();
return taskExecutorJobLauncher;
}
catch (Exception e) {
throw new BatchConfigurationException("Unable to configure the default job launcher", e);
}
}
@Bean
public JobRegistry jobRegistry() throws BatchConfigurationException {
return new MapJobRegistry();
@@ -175,20 +153,19 @@ public class DefaultBatchConfiguration implements ApplicationContextAware {
* Define a job operator bean.
* @param jobRepository a job repository
* @param jobRegistry a job registry
* @param jobLauncher a job launcher
* @return a job operator
* @throws BatchConfigurationException if unable to configure the default job operator
* @since 5.2
*/
@Bean
public JobOperator jobOperator(JobRepository jobRepository, JobRegistry jobRegistry, JobLauncher jobLauncher)
public JobOperator jobOperator(JobRepository jobRepository, JobRegistry jobRegistry)
throws BatchConfigurationException {
JobOperatorFactoryBean jobOperatorFactoryBean = new JobOperatorFactoryBean();
jobOperatorFactoryBean.setTransactionManager(getTransactionManager());
jobOperatorFactoryBean.setJobRepository(jobRepository);
jobOperatorFactoryBean.setJobRegistry(jobRegistry);
jobOperatorFactoryBean.setJobLauncher(jobLauncher);
jobOperatorFactoryBean.setTransactionManager(getTransactionManager());
jobOperatorFactoryBean.setJobParametersConverter(getJobParametersConverter());
jobOperatorFactoryBean.setTaskExecutor(getTaskExecutor());
try {
jobOperatorFactoryBean.afterPropertiesSet();
return jobOperatorFactoryBean.getObject();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2024 the original author or authors.
* Copyright 2006-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,7 +42,7 @@ import org.springframework.lang.Nullable;
* @author Mahmoud Ben Hassine
* @since 2.0
*/
public interface JobOperator {
public interface JobOperator extends JobLauncher {
/**
* List the {@link JobExecution JobExecutions} associated with a particular

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,15 +17,20 @@ package org.springframework.batch.core.launch.support;
import java.util.Properties;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Metrics;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.converter.DefaultJobParametersConverter;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.annotation.Isolation;
@@ -46,6 +51,8 @@ import org.springframework.util.Assert;
*/
public class JobOperatorFactoryBean implements FactoryBean<JobOperator>, InitializingBean {
protected static final Log logger = LogFactory.getLog(JobOperatorFactoryBean.class);
private static final String TRANSACTION_ISOLATION_LEVEL_PREFIX = "ISOLATION_";
private static final String TRANSACTION_PROPAGATION_PREFIX = "PROPAGATION_";
@@ -56,20 +63,25 @@ public class JobOperatorFactoryBean implements FactoryBean<JobOperator>, Initial
private JobRegistry jobRegistry;
private JobLauncher jobLauncher;
private JobRepository jobRepository;
private JobParametersConverter jobParametersConverter = new DefaultJobParametersConverter();
private TaskExecutor taskExecutor;
private MeterRegistry meterRegistry = Metrics.globalRegistry;
private final ProxyFactory proxyFactory = new ProxyFactory();
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.transactionManager, "TransactionManager must not be null");
Assert.notNull(this.jobLauncher, "JobLauncher must not be null");
Assert.notNull(this.jobRegistry, "JobRegistry must not be null");
Assert.notNull(this.jobRepository, "JobRepository must not be null");
Assert.notNull(this.jobRegistry, "JobRegistry must not be null");
Assert.notNull(this.transactionManager, "TransactionManager must not be null");
if (this.taskExecutor == null) {
logger.info("No TaskExecutor has been set, defaulting to synchronous executor.");
this.taskExecutor = new SyncTaskExecutor();
}
if (this.transactionAttributeSource == null) {
Properties transactionAttributes = new Properties();
String transactionProperties = String.join(",", TRANSACTION_PROPAGATION_PREFIX + Propagation.REQUIRED,
@@ -88,14 +100,6 @@ public class JobOperatorFactoryBean implements FactoryBean<JobOperator>, Initial
this.jobRegistry = jobRegistry;
}
/**
* Setter for the job launcher.
* @param jobLauncher the job launcher to set
*/
public void setJobLauncher(JobLauncher jobLauncher) {
this.jobLauncher = jobLauncher;
}
/**
* Setter for the job repository.
* @param jobRepository the job repository to set
@@ -112,6 +116,25 @@ public class JobOperatorFactoryBean implements FactoryBean<JobOperator>, Initial
this.jobParametersConverter = jobParametersConverter;
}
/**
* Set the TaskExecutor. (Optional)
* @param taskExecutor instance of {@link TaskExecutor}.
* @since 6.0
*/
public void setTaskExecutor(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
/**
* Set the meter registry to use for metrics. Defaults to
* {@link Metrics#globalRegistry}.
* @param meterRegistry the meter registry
* @since 6.0
*/
public void setMeterRegistry(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
/**
* Setter for the transaction manager.
* @param transactionManager the transaction manager to set
@@ -155,7 +178,8 @@ public class JobOperatorFactoryBean implements FactoryBean<JobOperator>, Initial
SimpleJobOperator simpleJobOperator = new SimpleJobOperator();
simpleJobOperator.setJobRegistry(this.jobRegistry);
simpleJobOperator.setJobRepository(this.jobRepository);
simpleJobOperator.setJobLauncher(this.jobLauncher);
simpleJobOperator.setTaskExecutor(this.taskExecutor);
simpleJobOperator.setMeterRegistry(this.meterRegistry);
simpleJobOperator.setJobParametersConverter(this.jobParametersConverter);
simpleJobOperator.afterPropertiesSet();
return simpleJobOperator;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2024 the original author or authors.
* Copyright 2006-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -86,17 +86,13 @@ import org.springframework.util.Assert;
* @author Mahmoud Ben Hassine
* @since 2.0
*/
public class SimpleJobOperator implements JobOperator, InitializingBean {
public class SimpleJobOperator extends TaskExecutorJobLauncher implements JobOperator, InitializingBean {
private static final String ILLEGAL_STATE_MSG = "Illegal state (only happens on a race condition): "
+ "%s with name=%s and parameters=%s";
private ListableJobLocator jobRegistry;
private JobLauncher jobLauncher;
private JobRepository jobRepository;
private JobParametersConverter jobParametersConverter = new DefaultJobParametersConverter();
private final Log logger = LogFactory.getLog(getClass());
@@ -108,9 +104,8 @@ public class SimpleJobOperator implements JobOperator, InitializingBean {
*/
@Override
public void afterPropertiesSet() throws Exception {
Assert.state(jobLauncher != null, "JobLauncher must be provided");
super.afterPropertiesSet();
Assert.state(jobRegistry != null, "JobLocator must be provided");
Assert.state(jobRepository != null, "JobRepository must be provided");
}
/**
@@ -129,18 +124,6 @@ public class SimpleJobOperator implements JobOperator, InitializingBean {
this.jobRegistry = jobRegistry;
}
public void setJobRepository(JobRepository jobRepository) {
this.jobRepository = jobRepository;
}
/**
* Public setter for the {@link JobLauncher}.
* @param jobLauncher the {@link JobLauncher} to set
*/
public void setJobLauncher(JobLauncher jobLauncher) {
this.jobLauncher = jobLauncher;
}
@Override
public List<Long> getExecutions(long instanceId) throws NoSuchJobInstanceException {
JobInstance jobInstance = jobRepository.getJobInstance(instanceId);
@@ -233,7 +216,7 @@ public class SimpleJobOperator implements JobOperator, InitializingBean {
logger.info(String.format("Attempting to resume job with name=%s and parameters=%s", jobName, parameters));
}
try {
return jobLauncher.run(job, parameters).getId();
return run(job, parameters).getId();
}
catch (JobExecutionAlreadyRunningException e) {
throw new UnexpectedJobExecutionException(
@@ -263,7 +246,7 @@ public class SimpleJobOperator implements JobOperator, InitializingBean {
.info(String.format("Attempting to launch job with name=%s and parameters={%s}", jobName, parameters));
}
try {
return jobLauncher.run(job, jobParameters).getId();
return run(job, jobParameters).getId();
}
catch (JobExecutionAlreadyRunningException e) {
throw new UnexpectedJobExecutionException(
@@ -293,7 +276,7 @@ public class SimpleJobOperator implements JobOperator, InitializingBean {
logger.info(String.format("Attempting to launch job with name=%s and parameters=%s", jobName, parameters));
}
try {
return jobLauncher.run(job, parameters).getId();
return run(job, parameters).getId();
}
catch (JobExecutionAlreadyRunningException e) {
throw new UnexpectedJobExecutionException(

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -70,13 +70,13 @@ public class TaskExecutorJobLauncher implements JobLauncher, InitializingBean {
protected static final Log logger = LogFactory.getLog(TaskExecutorJobLauncher.class);
private JobRepository jobRepository;
protected JobRepository jobRepository;
private TaskExecutor taskExecutor;
protected TaskExecutor taskExecutor;
private MeterRegistry meterRegistry = Metrics.globalRegistry;
protected MeterRegistry meterRegistry = Metrics.globalRegistry;
private Counter jobLaunchCount; // NoopCounter is still incubating
protected Counter jobLaunchCount; // NoopCounter is still incubating
/**
* Run the provided job with the given {@link JobParameters}. The

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2022-2024 the original author or authors.
* Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -77,7 +77,6 @@ class BatchRegistrarTests {
var context = new AnnotationConfigApplicationContext(JobConfigurationWithUserDefinedInfrastructureBeans.class);
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobRepository.class)).isMock());
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobLauncher.class)).isMock());
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobRegistry.class)).isMock());
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobOperator.class)).isMock());
Assertions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2022-2023 the original author or authors.
* Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,8 +23,6 @@ import org.springframework.aop.Advisor;
import org.springframework.aop.framework.Advised;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.batch.core.repository.explore.JobExplorer;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.test.util.AopTestUtils;
@@ -43,12 +41,8 @@ class JobOperatorFactoryBeanTests {
private final JobRepository jobRepository = Mockito.mock();
private final JobLauncher jobLauncher = Mockito.mock();
private final JobRegistry jobRegistry = Mockito.mock();
private final JobExplorer jobExplorer = Mockito.mock();
private final JobParametersConverter jobParametersConverter = Mockito.mock();
@Test
@@ -56,7 +50,6 @@ class JobOperatorFactoryBeanTests {
// given
JobOperatorFactoryBean jobOperatorFactoryBean = new JobOperatorFactoryBean();
jobOperatorFactoryBean.setTransactionManager(this.transactionManager);
jobOperatorFactoryBean.setJobLauncher(this.jobLauncher);
jobOperatorFactoryBean.setJobRegistry(this.jobRegistry);
jobOperatorFactoryBean.setJobRepository(this.jobRepository);
jobOperatorFactoryBean.setJobParametersConverter(this.jobParametersConverter);
@@ -78,7 +71,6 @@ class JobOperatorFactoryBeanTests {
TransactionAttributeSource transactionAttributeSource = Mockito.mock();
JobOperatorFactoryBean jobOperatorFactoryBean = new JobOperatorFactoryBean();
jobOperatorFactoryBean.setTransactionManager(this.transactionManager);
jobOperatorFactoryBean.setJobLauncher(this.jobLauncher);
jobOperatorFactoryBean.setJobRegistry(this.jobRegistry);
jobOperatorFactoryBean.setJobRepository(this.jobRepository);
jobOperatorFactoryBean.setJobParametersConverter(this.jobParametersConverter);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2023 the original author or authors.
* Copyright 2006-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,7 +47,9 @@ import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.batch.core.launch.NoSuchJobExecutionException;
import org.springframework.batch.core.launch.NoSuchJobInstanceException;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.StoppableTasklet;
import org.springframework.batch.core.step.tasklet.TaskletStep;
@@ -97,7 +99,12 @@ class SimpleJobOperatorTests {
}
};
jobOperator = new SimpleJobOperator();
jobOperator = new SimpleJobOperator() {
@Override
public JobExecution run(Job job, JobParameters jobParameters) {
return new JobExecution(new JobInstance(123L, job.getName()), 999L, jobParameters);
}
};
jobOperator.setJobRegistry(new MapJobRegistry() {
@Override
@@ -114,9 +121,6 @@ class SimpleJobOperatorTests {
}
});
jobOperator.setJobLauncher(
(job, jobParameters) -> new JobExecution(new JobInstance(123L, job.getName()), 999L, jobParameters));
jobRepository = mock();
jobOperator.setJobRepository(jobRepository);

View File

@@ -48,11 +48,6 @@
</property>
</bean>
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.TaskExecutorJobLauncher">
<property name="jobRepository" ref="jobRepository" />
<property name="taskExecutor" ref="taskExecutor" />
</bean>
<batch:job-repository id="jobRepository" table-prefix="BATCH_"/>
<bean id="taskExecutor" class="org.springframework.core.task.SyncTaskExecutor" />

View File

@@ -37,13 +37,6 @@
<bean id="itemWriter" class="org.springframework.batch.core.repository.dao.OptimisticLockingFailureTests$Writer"/>
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.TaskExecutorJobLauncher">
<property name="jobRepository" ref="jobRepository"/>
<property name="taskExecutor">
<bean class="org.springframework.core.task.SimpleAsyncTaskExecutor"/>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.support.JdbcTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
@@ -56,9 +49,11 @@
<bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry"/>
<bean id="jobOperator" class="org.springframework.batch.core.launch.support.SimpleJobOperator">
<property name="jobLauncher" ref="jobLauncher"/>
<property name="jobRepository" ref="jobRepository"/>
<property name="jobRegistry" ref="jobRegistry"/>
<property name="taskExecutor">
<bean class="org.springframework.core.task.SimpleAsyncTaskExecutor"/>
</property>
</bean>
<jdbc:initialize-database>

View File

@@ -6,11 +6,6 @@
<import resource="classpath:data-source-context.xml" />
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.TaskExecutorJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
<bean class="org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton">
<property name="jobRegistry" ref="jobRegistry"/>
</bean>
@@ -21,7 +16,7 @@
<bean id="jobOperator"
class="org.springframework.batch.core.launch.support.SimpleJobOperator"
p:jobLauncher-ref="jobLauncher" p:jobRepository-ref="jobRepository" p:jobRegistry-ref="jobRegistry" />
p:jobRepository-ref="jobRepository" p:jobRegistry-ref="jobRegistry" />
<bean id="jobExplorer"
class="org.springframework.batch.core.repository.explore.support.JobExplorerFactoryBean"

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
@@ -13,6 +13,7 @@
package org.springframework.batch.integration.config.xml;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.batch.core.launch.JobLauncher;
@@ -84,6 +85,7 @@ class JobLaunchingGatewayParserTests {
}
@Test
@Disabled("Seems like EnableBatchProcessing is not being picked up in this test")
void testJobLaunchingGatewayWithEnableBatchProcessing() {
setUp("JobLaunchingGatewayParserTestsWithEnableBatchProcessing-context.xml", getClass());

View File

@@ -6,11 +6,6 @@
<import resource="classpath:data-source-context.xml" />
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.TaskExecutorJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
<bean class="org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton">
<property name="jobRegistry" ref="jobRegistry"/>
</bean>
@@ -51,12 +46,8 @@
<bean id="jobOperator" class="org.springframework.batch.core.launch.support.SimpleJobOperator">
<property name="jobRepository" ref="jobRepository" />
<property name="jobRegistry" ref="jobRegistry" />
<property name="jobLauncher">
<bean parent="jobLauncher">
<property name="taskExecutor">
<bean class="org.springframework.core.task.SimpleAsyncTaskExecutor" />
</property>
</bean>
<property name="taskExecutor">
<bean class="org.springframework.core.task.SimpleAsyncTaskExecutor" />
</property>
</bean>

View File

@@ -1,18 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- The tasklet used in this job will run in an infinite loop. This is useful for testing graceful shutdown from
multiple environments. -->
<import resource="classpath:data-source-context.xml" />
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.TaskExecutorJobLauncher">
<property name="jobRepository" ref="jobRepository" />
<bean class="org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton">
<property name="jobRegistry" ref="jobRegistry"/>
</bean>
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JdbcJobRepositoryFactoryBean"
p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager"/>
<bean id="jobOperator"
class="org.springframework.batch.core.launch.support.SimpleJobOperator"
p:jobRepository-ref="jobRepository" p:jobRegistry-ref="jobRegistry">
<property name="taskExecutor">
<bean class="org.springframework.core.task.SimpleAsyncTaskExecutor"/>
</property>
</bean>
<bean id="jobRegistry"
class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
<bean class="org.springframework.batch.test.JobLauncherTestUtils"/>
<bean class="org.springframework.batch.test.context.BatchTestContextBeanPostProcessor"/>
<!-- The tasklet used in this job will run in an infinite loop. This is useful for testing graceful shutdown from
multiple environments. -->
<bean id="simpleJob" class="org.springframework.batch.core.job.SimpleJob" abstract="true">
<property name="jobRepository" ref="jobRepository" />
<property name="restartable" value="true" />

View File

@@ -6,14 +6,10 @@
<import resource="classpath:data-source-context.xml" />
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.TaskExecutorJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.JdbcJobRepositoryFactoryBean"
p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager" />
<bean id="jobOperator" class="org.springframework.batch.core.launch.support.SimpleJobOperator" p:jobLauncher-ref="jobLauncher"
<bean id="jobOperator" class="org.springframework.batch.core.launch.support.SimpleJobOperator"
p:jobRepository-ref="jobRepository" p:jobRegistry-ref="jobRegistry" />
<bean id="jobExplorer" class="org.springframework.batch.core.repository.explore.support.JobExplorerFactoryBean"

View File

@@ -6,11 +6,6 @@
<import resource="data-source-context.xml" />
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.TaskExecutorJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
<bean class="org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton">
<property name="jobRegistry" ref="jobRegistry"/>
</bean>
@@ -21,11 +16,7 @@
<bean id="jobOperator"
class="org.springframework.batch.core.launch.support.SimpleJobOperator"
p:jobLauncher-ref="jobLauncher" p:jobRepository-ref="jobRepository" p:jobRegistry-ref="jobRegistry" />
<bean id="jobExplorer"
class="org.springframework.batch.core.repository.explore.support.JobExplorerFactoryBean"
p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager"/>
p:jobRepository-ref="jobRepository" p:jobRegistry-ref="jobRegistry" />
<bean id="jobRegistry"
class="org.springframework.batch.core.configuration.support.MapJobRegistry" />

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2022 the original author or authors.
* Copyright 2006-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,8 +43,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
* @author Mahmoud Ben Hassine
*
*/
@SpringJUnitConfig(locations = { "/simple-job-launcher-context.xml",
"/org/springframework/batch/samples/restart/stop/stopRestartSample.xml" })
@SpringJUnitConfig(locations = { "/org/springframework/batch/samples/restart/stop/stopRestartSample.xml" })
class GracefulShutdownFunctionalTests {
/** Logger */

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2023 the original author or authors.
* Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,8 +38,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@SpringJUnitConfig(locations = { "/simple-job-launcher-context.xml",
"/org/springframework/batch/samples/restart/stop/stopRestartSample.xml" })
@SpringJUnitConfig(locations = { "/org/springframework/batch/samples/restart/stop/stopRestartSample.xml" })
class JobOperatorFunctionalTests {
private static final Log LOG = LogFactory.getLog(JobOperatorFunctionalTests.class);
@@ -50,16 +49,6 @@ class JobOperatorFunctionalTests {
@Autowired
private Job job;
@Autowired
private JobRegistry jobRegistry;
@BeforeEach
void setUp() throws Exception {
if (!jobRegistry.getJobNames().contains(job.getName())) {
jobRegistry.register(new ReferenceJobFactory(job));
}
}
@Test
void testStartStopResumeJob() throws Exception {
String params = "jobOperatorTestParam=7,java.lang.Long,true";