Make MapJobRegistry smart to auto register jobs at startup
Before this commit, it was required to populate the job registry with a different component (like a bean post processor or a smart initializing singleton) before being able to use it with the JobOperator. This commit makes the `MapJobRegistry` smart enough to auto register jobs defined in the application context. This removes the need for a distinct component to populate the registry and therefore simplifies the configuration. This commit also: - removes the usage of `JobFactory` from `JobRegistry` - deprecates JobRegistrySmartInitializingSingleton and removes its configuration from the default batch configuration Resolves #4854 Resolves #4855 Resolves #4856
This commit is contained in:
@@ -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.
|
||||
@@ -22,17 +22,18 @@ import org.springframework.batch.core.Job;
|
||||
* <code>name</code>.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Mahmoud Ben Hassine
|
||||
*
|
||||
*/
|
||||
public interface JobRegistry extends ListableJobLocator {
|
||||
|
||||
/**
|
||||
* Registers a {@link Job} at runtime.
|
||||
* @param jobFactory the {@link Job} to be registered
|
||||
* @throws DuplicateJobException if a factory with the same job name has already been
|
||||
* @param job the {@link Job} to be registered
|
||||
* @throws DuplicateJobException if a job with the same name has already been
|
||||
* registered.
|
||||
*/
|
||||
void register(JobFactory jobFactory) throws DuplicateJobException;
|
||||
void register(Job job) throws DuplicateJobException;
|
||||
|
||||
/**
|
||||
* Unregisters a previously registered {@link Job}. If it was not previously
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.batch.core.configuration.support.AutomaticJobRegistrar;
|
||||
import org.springframework.batch.core.configuration.support.DefaultJobLoader;
|
||||
import org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton;
|
||||
import org.springframework.batch.core.configuration.support.MapJobRegistry;
|
||||
import org.springframework.batch.core.launch.support.JobOperatorFactoryBean;
|
||||
import org.springframework.batch.core.repository.support.JdbcJobRepositoryFactoryBean;
|
||||
@@ -70,7 +69,6 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
.synthesize();
|
||||
registerJobRepository(registry, importingClassMetadata);
|
||||
registerJobRegistry(registry);
|
||||
registerJobRegistrySmartInitializingSingleton(registry);
|
||||
registerJobOperator(registry, batchAnnotation);
|
||||
registerAutomaticJobRegistrar(registry, batchAnnotation);
|
||||
watch.stop();
|
||||
@@ -220,21 +218,6 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
registry.registerBeanDefinition(JOB_REGISTRY, beanDefinition);
|
||||
}
|
||||
|
||||
private void registerJobRegistrySmartInitializingSingleton(BeanDefinitionRegistry registry) {
|
||||
if (registry.containsBeanDefinition("jobRegistrySmartInitializingSingleton")) {
|
||||
LOGGER
|
||||
.info("Bean jobRegistrySmartInitializingSingleton already defined in the application context, skipping"
|
||||
+ " the registration of a jobRegistrySmartInitializingSingleton");
|
||||
return;
|
||||
}
|
||||
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(JobRegistrySmartInitializingSingleton.class);
|
||||
beanDefinitionBuilder.addPropertyReference(JOB_REGISTRY, JOB_REGISTRY);
|
||||
|
||||
registry.registerBeanDefinition("jobRegistrySmartInitializingSingleton",
|
||||
beanDefinitionBuilder.getBeanDefinition());
|
||||
}
|
||||
|
||||
private void registerJobOperator(BeanDefinitionRegistry registry, EnableBatchProcessing batchAnnotation) {
|
||||
if (registry.containsBeanDefinition(JOB_OPERATOR)) {
|
||||
LOGGER.info("Bean jobOperator already defined in the application context, skipping"
|
||||
|
||||
@@ -50,8 +50,6 @@ import org.springframework.transaction.annotation.Isolation;
|
||||
* <li>a {@link ResourcelessJobRepository} named "jobRepository"</li>
|
||||
* <li>a {@link MapJobRegistry} named "jobRegistry"</li>
|
||||
* <li>a {@link TaskExecutorJobOperator} named "JobOperator"</li>
|
||||
* <li>a {@link JobRegistrySmartInitializingSingleton} named
|
||||
* "jobRegistrySmartInitializingSingleton"</li>
|
||||
* <li>a {@link org.springframework.batch.core.scope.StepScope} named "stepScope"</li>
|
||||
* <li>a {@link org.springframework.batch.core.scope.JobScope} named "jobScope"</li>
|
||||
* </ul>
|
||||
@@ -117,21 +115,6 @@ public class DefaultBatchConfiguration implements ApplicationContextAware {
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton(JobRegistry jobRegistry)
|
||||
throws BatchConfigurationException {
|
||||
JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton = new JobRegistrySmartInitializingSingleton();
|
||||
jobRegistrySmartInitializingSingleton.setJobRegistry(jobRegistry);
|
||||
try {
|
||||
jobRegistrySmartInitializingSingleton.afterPropertiesSet();
|
||||
return jobRegistrySmartInitializingSingleton;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new BatchConfigurationException(
|
||||
"Unable to configure the default job registry SmartInitializingSingleton", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction manager to use for the job operator. Defaults to
|
||||
* {@link ResourcelessTransactionManager}.
|
||||
|
||||
@@ -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.
|
||||
@@ -27,7 +27,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.configuration.DuplicateJobException;
|
||||
import org.springframework.batch.core.configuration.JobFactory;
|
||||
import org.springframework.batch.core.configuration.JobRegistry;
|
||||
import org.springframework.batch.core.configuration.StepRegistry;
|
||||
import org.springframework.batch.core.launch.NoSuchJobException;
|
||||
@@ -251,8 +250,7 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
|
||||
* @throws DuplicateJobException if that job is already registered
|
||||
*/
|
||||
private void doRegister(ConfigurableApplicationContext context, Job job) throws DuplicateJobException {
|
||||
final JobFactory jobFactory = new ReferenceJobFactory(job);
|
||||
jobRegistry.register(jobFactory);
|
||||
jobRegistry.register(job);
|
||||
|
||||
if (stepRegistry != null) {
|
||||
if (!(job instanceof StepLocator)) {
|
||||
|
||||
@@ -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.
|
||||
@@ -27,6 +27,7 @@ import org.springframework.batch.core.configuration.JobRegistry;
|
||||
* Generic service that can bind and unbind a {@link JobFactory} in a {@link JobRegistry}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Mahmoud Ben Hassine
|
||||
*
|
||||
*/
|
||||
public class JobFactoryRegistrationListener {
|
||||
@@ -53,7 +54,7 @@ public class JobFactoryRegistrationListener {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Binding JobFactory: " + jobFactory.getJobName());
|
||||
}
|
||||
jobRegistry.register(jobFactory);
|
||||
jobRegistry.register(jobFactory.createJob());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -45,7 +45,10 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Henning Pöttker
|
||||
* @since 5.1.1
|
||||
* @deprecated since 6.0 with no replacement. Register a {@link MapJobRegistry} as a bean,
|
||||
* and it will automatically register all {@link Job} beans in the application context.
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
public class JobRegistrySmartInitializingSingleton
|
||||
implements SmartInitializingSingleton, BeanFactoryAware, InitializingBean, DisposableBean {
|
||||
|
||||
@@ -143,12 +146,11 @@ public class JobRegistrySmartInitializingSingleton
|
||||
groupName = getGroupName(defaultListableBeanFactory.getBeanDefinition(beanName), job);
|
||||
}
|
||||
job = groupName == null ? job : new GroupAwareJob(groupName, job);
|
||||
ReferenceJobFactory jobFactory = new ReferenceJobFactory(job);
|
||||
String name = jobFactory.getJobName();
|
||||
String name = job.getName();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Registering job: " + name);
|
||||
}
|
||||
jobRegistry.register(jobFactory);
|
||||
jobRegistry.register(job);
|
||||
jobNames.add(name);
|
||||
}
|
||||
catch (DuplicateJobException e) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2019 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.
|
||||
@@ -16,68 +16,89 @@
|
||||
package org.springframework.batch.core.configuration.support;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.configuration.DuplicateJobException;
|
||||
import org.springframework.batch.core.configuration.JobFactory;
|
||||
import org.springframework.batch.core.configuration.JobRegistry;
|
||||
import org.springframework.batch.core.launch.NoSuchJobException;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple, thread-safe, map-based implementation of {@link JobRegistry}.
|
||||
* Simple, thread-safe, map-based implementation of {@link JobRegistry}. This registry is
|
||||
* a {@link SmartInitializingSingleton} that is automatically populated with all
|
||||
* {@link Job} beans in the {@link ApplicationContext}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Robert Fischer
|
||||
* @author Mahmoud Ben Hassine
|
||||
*/
|
||||
public class MapJobRegistry implements JobRegistry {
|
||||
public class MapJobRegistry implements JobRegistry, SmartInitializingSingleton, ApplicationContextAware {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/**
|
||||
* The map holding the registered job factories.
|
||||
* The map holding the registered jobs.
|
||||
*/
|
||||
// The "final" ensures that it is visible and initialized when the constructor
|
||||
// resolves.
|
||||
private final ConcurrentMap<String, JobFactory> map = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<String, Job> map = new ConcurrentHashMap<>();
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
public void register(JobFactory jobFactory) throws DuplicateJobException {
|
||||
Assert.notNull(jobFactory, "jobFactory is null");
|
||||
String name = jobFactory.getJobName();
|
||||
Assert.notNull(name, "Job configuration must have a name.");
|
||||
JobFactory previousValue = map.putIfAbsent(name, jobFactory);
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
Map<String, Job> jobBeans = this.applicationContext.getBeansOfType(Job.class);
|
||||
this.map.putAll(jobBeans);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Job job) throws DuplicateJobException {
|
||||
Assert.notNull(job, "job must not be null");
|
||||
String jobName = job.getName();
|
||||
Assert.notNull(jobName, "Job name must not be null");
|
||||
Job previousValue = this.map.putIfAbsent(jobName, job);
|
||||
if (previousValue != null) {
|
||||
throw new DuplicateJobException("A job configuration with this name [" + name + "] was already registered");
|
||||
throw new DuplicateJobException("A job with this name [" + jobName + "] was already registered");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(String name) {
|
||||
Assert.notNull(name, "Job configuration must have a name.");
|
||||
map.remove(name);
|
||||
Assert.notNull(name, "Job name must not be null");
|
||||
this.map.remove(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Job getJob(@Nullable String name) throws NoSuchJobException {
|
||||
JobFactory factory = map.get(name);
|
||||
if (factory == null) {
|
||||
throw new NoSuchJobException("No job configuration with the name [" + name + "] was registered");
|
||||
Job job = this.map.get(name);
|
||||
if (job == null) {
|
||||
throw new NoSuchJobException("No job with the name [" + name + "] was registered");
|
||||
}
|
||||
else {
|
||||
return factory.createJob();
|
||||
return job;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an unmodifiable view of the job names.
|
||||
* Provides an unmodifiable view of job names.
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getJobNames() {
|
||||
return Collections.unmodifiableSet(map.keySet());
|
||||
return Collections.unmodifiableSet(this.map.keySet());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.batch.core.DefaultJobKeyGenerator;
|
||||
import org.springframework.batch.core.JobKeyGenerator;
|
||||
import org.springframework.batch.core.configuration.JobRegistry;
|
||||
import org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton;
|
||||
import org.springframework.batch.core.converter.DefaultJobParametersConverter;
|
||||
import org.springframework.batch.core.converter.JobParametersConverter;
|
||||
import org.springframework.batch.core.converter.JsonJobParametersConverter;
|
||||
@@ -64,8 +63,6 @@ class BatchRegistrarTests {
|
||||
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobRepository.class)).isMock());
|
||||
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobRegistry.class)).isMock());
|
||||
Assertions.assertTrue(Mockito.mockingDetails(context.getBean(JobOperator.class)).isMock());
|
||||
Assertions
|
||||
.assertTrue(Mockito.mockingDetails(context.getBean(JobRegistrySmartInitializingSingleton.class)).isMock());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -147,15 +144,12 @@ class BatchRegistrarTests {
|
||||
JobRepository jobRepository = context.getBean(JobRepository.class);
|
||||
JobRegistry jobRegistry = context.getBean(JobRegistry.class);
|
||||
JobOperator jobOperator = context.getBean(JobOperator.class);
|
||||
JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton = context
|
||||
.getBean(JobRegistrySmartInitializingSingleton.class);
|
||||
|
||||
// then
|
||||
Assertions.assertNotNull(jobLauncher);
|
||||
Assertions.assertNotNull(jobRepository);
|
||||
Assertions.assertNotNull(jobRegistry);
|
||||
Assertions.assertNotNull(jobOperator);
|
||||
Assertions.assertNotNull(jobRegistrySmartInitializingSingleton);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -236,11 +230,6 @@ class BatchRegistrarTests {
|
||||
return Mockito.mock();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton() {
|
||||
return Mockito.mock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
@@ -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.
|
||||
@@ -36,7 +36,6 @@ import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.step.builder.StepBuilder;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -72,9 +71,6 @@ class DefaultBatchConfigurationTests {
|
||||
Assertions.assertEquals(1, jobRepositories.size());
|
||||
JobRepository jobRepository = jobRepositories.entrySet().iterator().next().getValue();
|
||||
Assertions.assertInstanceOf(DummyJobRepository.class, jobRepository);
|
||||
Map<String, JobRegistrySmartInitializingSingleton> jobRegistrySmartInitializingSingletonMap = context
|
||||
.getBeansOfType(JobRegistrySmartInitializingSingleton.class);
|
||||
Assertions.assertEquals(1, jobRegistrySmartInitializingSingletonMap.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -87,15 +83,12 @@ class DefaultBatchConfigurationTests {
|
||||
JobRepository jobRepository = context.getBean(JobRepository.class);
|
||||
JobRegistry jobRegistry = context.getBean(JobRegistry.class);
|
||||
JobOperator jobOperator = context.getBean(JobOperator.class);
|
||||
JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton = context
|
||||
.getBean(JobRegistrySmartInitializingSingleton.class);
|
||||
|
||||
// then
|
||||
Assertions.assertNotNull(jobLauncher);
|
||||
Assertions.assertNotNull(jobRepository);
|
||||
Assertions.assertNotNull(jobRegistry);
|
||||
Assertions.assertNotNull(jobOperator);
|
||||
Assertions.assertNotNull(jobRegistrySmartInitializingSingleton);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -136,13 +129,6 @@ class DefaultBatchConfigurationTests {
|
||||
return new DummyJobRepository();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JobRegistrySmartInitializingSingleton jobRegistrySmartInitializingSingleton(JobRegistry jobRegistry) {
|
||||
JobRegistrySmartInitializingSingleton smartInitializingSingleton = new JobRegistrySmartInitializingSingleton();
|
||||
smartInitializingSingleton.setJobRegistry(jobRegistry);
|
||||
return smartInitializingSingleton;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
@@ -20,9 +20,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.configuration.JobFactory;
|
||||
import org.springframework.batch.core.test.repository.JobSupport;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Mahmoud Ben Hassine
|
||||
*
|
||||
*/
|
||||
class JobFactoryRegistrationListenerTests {
|
||||
@@ -37,7 +39,7 @@ class JobFactoryRegistrationListenerTests {
|
||||
listener.bind(new JobFactory() {
|
||||
@Override
|
||||
public Job createJob() {
|
||||
return null;
|
||||
return new JobSupport("foo");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,7 +56,7 @@ class JobFactoryRegistrationListenerTests {
|
||||
listener.unbind(new JobFactory() {
|
||||
@Override
|
||||
public Job createJob() {
|
||||
return null;
|
||||
return new JobSupport("foo");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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.
|
||||
@@ -25,6 +25,7 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Mahmoud Ben Hassine
|
||||
*
|
||||
*/
|
||||
@SpringJUnitConfig
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
* Copyright 2024-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.
|
||||
@@ -26,11 +26,9 @@ import org.springframework.batch.core.configuration.JobRegistry;
|
||||
import org.springframework.batch.core.job.JobSupport;
|
||||
import org.springframework.beans.FatalBeanException;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
@@ -95,28 +93,4 @@ class JobRegistrySmartInitializingSingletonTests {
|
||||
assertTrue(jobRegistry.getJobNames().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecutionWithApplicationContext() throws Exception {
|
||||
var context = new ClassPathXmlApplicationContext("test-context-with-smart-initializing-singleton.xml",
|
||||
getClass());
|
||||
var registry = context.getBean("registry", JobRegistry.class);
|
||||
Collection<String> jobNames = registry.getJobNames();
|
||||
String[] names = context.getBeanNamesForType(JobSupport.class);
|
||||
int count = names.length;
|
||||
// Each concrete bean of type JobConfiguration is registered...
|
||||
assertEquals(count, jobNames.size());
|
||||
// N.B. there is a failure / wonky mode where a parent bean is given an
|
||||
// explicit name or beanName (using property setter): in this case then
|
||||
// child beans will have the same name and will be re-registered (and
|
||||
// override, if the registry supports that).
|
||||
assertNotNull(registry.getJob("test-job"));
|
||||
assertEquals(context.getBean("test-job-with-name"), registry.getJob("foo"));
|
||||
assertEquals(context.getBean("test-job-with-bean-name"), registry.getJob("bar"));
|
||||
assertEquals(context.getBean("test-job-with-parent-and-name"), registry.getJob("spam"));
|
||||
assertEquals(context.getBean("test-job-with-parent-and-bean-name"), registry.getJob("bucket"));
|
||||
assertEquals(context.getBean("test-job-with-concrete-parent"), registry.getJob("maps"));
|
||||
assertEquals(context.getBean("test-job-with-concrete-parent-and-name"), registry.getJob("oof"));
|
||||
assertEquals(context.getBean("test-job-with-concrete-parent-and-bean-name"), registry.getJob("rab"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -15,21 +15,19 @@
|
||||
*/
|
||||
package org.springframework.batch.core.configuration.support;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.configuration.DuplicateJobException;
|
||||
import org.springframework.batch.core.configuration.JobFactory;
|
||||
import org.springframework.batch.core.job.JobSupport;
|
||||
import org.springframework.batch.core.launch.NoSuchJobException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Mahmoud Ben Hassine
|
||||
*
|
||||
*/
|
||||
class MapJobRegistryTests {
|
||||
@@ -38,7 +36,7 @@ class MapJobRegistryTests {
|
||||
|
||||
@Test
|
||||
void testUnregister() throws Exception {
|
||||
registry.register(new ReferenceJobFactory(new JobSupport("foo")));
|
||||
registry.register(new JobSupport("foo"));
|
||||
assertNotNull(registry.getJob("foo"));
|
||||
registry.unregister("foo");
|
||||
Exception exception = assertThrows(NoSuchJobException.class, () -> registry.getJob("foo"));
|
||||
@@ -47,28 +45,30 @@ class MapJobRegistryTests {
|
||||
|
||||
@Test
|
||||
void testReplaceDuplicateConfiguration() throws Exception {
|
||||
registry.register(new ReferenceJobFactory(new JobSupport("foo")));
|
||||
JobFactory jobFactory = new ReferenceJobFactory(new JobSupport("foo"));
|
||||
Exception exception = assertThrows(DuplicateJobException.class, () -> registry.register(jobFactory));
|
||||
registry.register(new JobSupport("foo"));
|
||||
Job job = new JobSupport("foo");
|
||||
Exception exception = assertThrows(DuplicateJobException.class, () -> registry.register(job));
|
||||
assertTrue(exception.getMessage().contains("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRealDuplicateConfiguration() throws Exception {
|
||||
JobFactory jobFactory = new ReferenceJobFactory(new JobSupport("foo"));
|
||||
registry.register(jobFactory);
|
||||
Exception exception = assertThrows(DuplicateJobException.class, () -> registry.register(jobFactory));
|
||||
Job job = new JobSupport("foo");
|
||||
registry.register(job);
|
||||
Exception exception = assertThrows(DuplicateJobException.class, () -> registry.register(job));
|
||||
assertTrue(exception.getMessage().contains("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetJobConfigurations() throws Exception {
|
||||
JobFactory jobFactory = new ReferenceJobFactory(new JobSupport("foo"));
|
||||
registry.register(jobFactory);
|
||||
registry.register(new ReferenceJobFactory(new JobSupport("bar")));
|
||||
Job job1 = new JobSupport("foo");
|
||||
Job job2 = new JobSupport("bar");
|
||||
registry.register(job1);
|
||||
registry.register(job2);
|
||||
Collection<String> configurations = registry.getJobNames();
|
||||
assertEquals(2, configurations.size());
|
||||
assertTrue(configurations.contains(jobFactory.getJobName()));
|
||||
assertTrue(configurations.contains(job1.getName()));
|
||||
assertTrue(configurations.contains(job2.getName()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2022 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
|
||||
<bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry"/>
|
||||
|
||||
<bean class="org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton">
|
||||
<property name="jobRegistry" ref="jobRegistry"/>
|
||||
</bean>
|
||||
|
||||
<batch:job-repository id="jobRepository" table-prefix="BATCH_"/>
|
||||
|
||||
<bean id="jobExplorer" class="org.springframework.batch.core.repository.explore.support.JobExplorerFactoryBean">
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
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">
|
||||
|
||||
<bean
|
||||
class="org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton">
|
||||
<property name="jobRegistry" ref="registry" />
|
||||
</bean>
|
||||
|
||||
<bean id="registry"
|
||||
class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
|
||||
|
||||
<bean id="test-job"
|
||||
class="org.springframework.batch.core.job.JobSupport">
|
||||
<property name="steps">
|
||||
<bean id="step1" class="org.springframework.batch.core.step.factory.SimpleStepFactoryBean">
|
||||
<property name="itemReader" ref="itemReader" />
|
||||
<property name="itemWriter" ref="itemWriter" />
|
||||
<property name="jobRepository" ref="jobRepository" />
|
||||
<property name="transactionManager" ref="transactionManager"/>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="itemReader"
|
||||
class="org.springframework.batch.item.support.ListItemReader">
|
||||
<constructor-arg value="foo,bar,spam" />
|
||||
</bean>
|
||||
|
||||
<bean id="itemWriter"
|
||||
class="org.springframework.batch.core.launch.EmptyItemWriter" />
|
||||
|
||||
<bean id="jobRepository"
|
||||
class="org.springframework.batch.core.step.JobRepositorySupport" />
|
||||
|
||||
<bean id="transactionManager"
|
||||
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
|
||||
|
||||
<bean id="test-job-with-name"
|
||||
class="org.springframework.batch.core.job.JobSupport">
|
||||
<property name="name" value="foo" />
|
||||
</bean>
|
||||
|
||||
<bean id="test-job-with-bean-name"
|
||||
class="org.springframework.batch.core.job.JobSupport">
|
||||
<property name="beanName" value="bar" />
|
||||
</bean>
|
||||
|
||||
<bean id="abstract-job"
|
||||
class="org.springframework.batch.core.job.JobSupport"
|
||||
abstract="true" />
|
||||
|
||||
<bean id="test-job-with-parent" parent="abstract-job" />
|
||||
|
||||
<bean id="test-job-with-parent-and-name" parent="abstract-job"
|
||||
p:name="spam" />
|
||||
|
||||
<bean id="test-job-with-parent-and-bean-name" parent="abstract-job"
|
||||
p:name="bucket" />
|
||||
|
||||
<bean id="parent-job"
|
||||
class="org.springframework.batch.core.job.JobSupport" />
|
||||
|
||||
<bean id="test-job-with-concrete-parent" parent="parent-job"
|
||||
p:name="maps" />
|
||||
|
||||
<bean id="test-job-with-concrete-parent-and-name"
|
||||
parent="parent-job" p:name="oof" />
|
||||
|
||||
<bean id="test-job-with-concrete-parent-and-bean-name"
|
||||
parent="parent-job" p:beanName="rab" />
|
||||
|
||||
</beans>
|
||||
@@ -19,10 +19,6 @@
|
||||
|
||||
<bean id="jobRegistry"
|
||||
class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
|
||||
<bean
|
||||
class="org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton">
|
||||
<property name="jobRegistry" ref="jobRegistry" />
|
||||
</bean>
|
||||
|
||||
<batch:job id="job2">
|
||||
<batch:step id="j2.s1" parent="step1" />
|
||||
|
||||
@@ -38,8 +38,4 @@
|
||||
|
||||
<bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry"/>
|
||||
|
||||
<bean class="org.springframework.batch.core.configuration.support.JobRegistrySmartInitializingSingleton">
|
||||
<property name="jobRegistry" ref="jobRegistry"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
Reference in New Issue
Block a user