Conditionally add custom scopes when using XML configuration

When using a combination of Java configuration and the XML namespace
configuration, prior to this commit, we would add the batch custom
scopes twice which lead to issues.  This commit gives priority to the
custom scopes provided by the java configuration.  If you've used
@EnableBatchProcessing and have configured batch components using the
batch namespace, the custom scopes that come with the java config will
take precidence.

This commit addresses Jira BATCH-2266
This commit is contained in:
Michael Minella
2014-09-22 13:45:43 -05:00
parent fc2431332b
commit a2f2df0b17
4 changed files with 71 additions and 16 deletions

View File

@@ -20,8 +20,9 @@ import org.springframework.batch.core.configuration.support.MapJobRegistry;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.scope.JobScope;
import org.springframework.batch.core.scope.StepScope;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@@ -30,8 +31,6 @@ import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.Assert;
import org.springframework.batch.core.scope.JobScope;
import org.springframework.batch.core.scope.StepScope;
import javax.sql.DataSource;
import java.util.Collection;
@@ -41,6 +40,7 @@ import java.util.Collection;
* available by implementing the {@link BatchConfigurer} interface. {@link BatchConfigurer}.
*
* @author Dave Syer
* @author Michael Minella
* @since 2.2
* @see EnableBatchProcessing
*/
@@ -48,9 +48,6 @@ import java.util.Collection;
@Import(ScopeConfiguration.class)
public abstract class AbstractBatchConfiguration implements ImportAware {
@Autowired
private ApplicationContext context;
@Autowired(required = false)
private Collection<DataSource> dataSources;

View File

@@ -15,9 +15,6 @@
*/
package org.springframework.batch.core.configuration.xml;
import java.util.Comparator;
import java.util.Map;
import org.springframework.batch.core.job.flow.support.DefaultStateTransitionComparator;
import org.springframework.batch.core.job.flow.support.StateTransition;
import org.springframework.beans.PropertyValue;
@@ -31,6 +28,9 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import java.util.Comparator;
import java.util.Map;
/**
* Utility methods used in parsing of the batch core namespace
*
@@ -41,7 +41,9 @@ public class CoreNamespaceUtils {
private static final String STEP_SCOPE_PROCESSOR_BEAN_NAME = "org.springframework.batch.core.scope.internalStepScope";
private static final String STEP_SCOPE_PROCESSOR_CLASS_NAME = "org.springframework.batch.core.scope.StepScope";
private static final String XML_CONFIG_STEP_SCOPE_PROCESSOR_CLASS_NAME = "org.springframework.batch.core.scope.StepScope";
private static final String JAVA_CONFIG_SCOPE_CLASS_NAME = "org.springframework.batch.core.configuration.annotation.ScopeConfiguration";
private static final String JOB_SCOPE_PROCESSOR_BEAN_NAME = "org.springframework.batch.core.scope.internalJobScope";
@@ -56,6 +58,7 @@ public class CoreNamespaceUtils {
private static final String CORE_NAMESPACE_POST_PROCESSOR_CLASS_NAME = "org.springframework.batch.core.configuration.xml.CoreNamespacePostProcessor";
public static void autoregisterBeansForNamespace(ParserContext parserContext, Object source) {
System.out.println("******** CoreNamespaceUtils is called");
checkForStepScope(parserContext, source);
checkForJobScope(parserContext, source);
addRangePropertyEditor(parserContext);
@@ -64,7 +67,7 @@ public class CoreNamespaceUtils {
}
private static void checkForStepScope(ParserContext parserContext, Object source) {
checkForScope(parserContext, source, STEP_SCOPE_PROCESSOR_CLASS_NAME, STEP_SCOPE_PROCESSOR_BEAN_NAME);
checkForScope(parserContext, source, XML_CONFIG_STEP_SCOPE_PROCESSOR_CLASS_NAME, STEP_SCOPE_PROCESSOR_BEAN_NAME);
}
private static void checkForJobScope(ParserContext parserContext, Object source) {
@@ -77,7 +80,7 @@ public class CoreNamespaceUtils {
String[] beanNames = parserContext.getRegistry().getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition bd = parserContext.getRegistry().getBeanDefinition(beanName);
if (scopeClassName.equals(bd.getBeanClassName())) {
if (scopeClassName.equals(bd.getBeanClassName()) || JAVA_CONFIG_SCOPE_CLASS_NAME.equals(bd.getBeanClassName())) {
foundScope = true;
break;
}

View File

@@ -16,29 +16,35 @@
package org.springframework.batch.core.configuration.annotation;
import static org.junit.Assert.assertEquals;
import java.util.concurrent.Callable;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.concurrent.Callable;
import static org.junit.Assert.assertEquals;
/**
* @author Dave Syer
* @author Michael Minella
*
*/
public class StepScopeConfigurationTests {
@@ -85,6 +91,16 @@ public class StepScopeConfigurationTests {
assertEquals("STEP", value.call());
}
@Test
public void testStepScopeXmlImportUsingNamespace() throws Exception {
init(StepScopeConfigurationXmlImportUsingNamespace.class);
SimpleHolder value = (SimpleHolder) context.getBean("xmlValue");
assertEquals("STEP", value.call());
value = (SimpleHolder) context.getBean("javaValue");
assertEquals("STEP", value.call());
}
@Test
public void testStepScopeWithProxyTargetClassInjected() throws Exception {
init(StepScopeConfigurationInjectingProxy.class);
@@ -199,6 +215,20 @@ public class StepScopeConfigurationTests {
}
@Configuration
@ImportResource("org/springframework/batch/core/configuration/annotation/StepScopeConfigurationTestsXmlImportUsingNamespace-context.xml")
@EnableBatchProcessing
public static class StepScopeConfigurationXmlImportUsingNamespace {
@Bean
@StepScope
protected SimpleHolder javaValue(@Value("#{stepExecution.stepName}")
final String value) {
return new SimpleHolder(value);
}
}
@Configuration
@EnableBatchProcessing
public static class StepScopeConfigurationInjectingProxy {
@@ -256,4 +286,11 @@ public class StepScopeConfigurationTests {
}
public static class TaskletSupport implements Tasklet {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
return RepeatStatus.FINISHED;
}
}
}

View File

@@ -0,0 +1,18 @@
<?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 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd">
<bean id="tasklet" class="org.springframework.batch.core.configuration.annotation.StepScopeConfigurationTests$TaskletSupport"/>
<job id="job" xmlns="http://www.springframework.org/schema/batch">
<step id="step1">
<tasklet ref="tasklet"/>
</step>
</job>
<bean id="xmlValue" class="org.springframework.batch.core.configuration.annotation.StepScopeConfigurationTests.SimpleHolder" scope="step">
<constructor-arg value="#{stepExecution.stepName}" />
</bean>
</beans>