diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/step/MapRepositoryFaultTolerantStepFactoryBeanRollbackTests.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/step/MapRepositoryFaultTolerantStepFactoryBeanRollbackTests.java index 0ec70a40d..033547deb 100644 --- a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/step/MapRepositoryFaultTolerantStepFactoryBeanRollbackTests.java +++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/step/MapRepositoryFaultTolerantStepFactoryBeanRollbackTests.java @@ -15,7 +15,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobParameters; @@ -29,18 +28,14 @@ import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.ParseException; import org.springframework.batch.item.UnexpectedInputException; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.batch.support.transaction.ResourcelessTransactionManager; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.util.Assert; /** * Tests for {@link FaultTolerantStepFactoryBean}. */ -@ContextConfiguration(locations = "/simple-job-launcher-context.xml") -@RunWith(SpringJUnit4ClassRunner.class) public class MapRepositoryFaultTolerantStepFactoryBeanRollbackTests { private static final int MAX_COUNT = 1000; @@ -61,24 +56,20 @@ public class MapRepositoryFaultTolerantStepFactoryBeanRollbackTests { private JobRepository repository; - @Autowired - private PlatformTransactionManager transactionManager; + private PlatformTransactionManager transactionManager = new ResourcelessTransactionManager(); @SuppressWarnings("unchecked") @Before public void setUp() throws Exception { - repository = new MapJobRepositoryFactoryBean().getJobRepository(); - reader = new SkipReaderStub(); writer = new SkipWriterStub(); processor = new SkipProcessorStub(); factory = new FaultTolerantStepFactoryBean(); - factory.setBeanName("stepName"); factory.setTransactionManager(transactionManager); - factory.setJobRepository(repository); + factory.setBeanName("stepName"); factory.setCommitInterval(3); ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(3); @@ -113,7 +104,7 @@ public class MapRepositoryFaultTolerantStepFactoryBeanRollbackTests { if (i%100==0) { logger.info("Starting step: "+i); - repository = new MapJobRepositoryFactoryBean().getJobRepository(); + repository = new MapJobRepositoryFactoryBean(transactionManager).getJobRepository(); factory.setJobRepository(repository); jobExecution = repository.createJobExecution("vanillaJob", new JobParameters()); } diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/step/MapRepositoryFaultTolerantStepFactoryBeanTests.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/step/MapRepositoryFaultTolerantStepFactoryBeanTests.java index 7b4d167c4..58ca3a330 100644 --- a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/step/MapRepositoryFaultTolerantStepFactoryBeanTests.java +++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/step/MapRepositoryFaultTolerantStepFactoryBeanTests.java @@ -13,7 +13,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobParameters; @@ -27,18 +26,14 @@ import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.ParseException; import org.springframework.batch.item.UnexpectedInputException; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.batch.support.transaction.ResourcelessTransactionManager; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.util.Assert; /** * Tests for {@link FaultTolerantStepFactoryBean}. */ -@ContextConfiguration(locations = "/simple-job-launcher-context.xml") -@RunWith(SpringJUnit4ClassRunner.class) public class MapRepositoryFaultTolerantStepFactoryBeanTests { private static final int MAX_COUNT = 1000; @@ -59,14 +54,11 @@ public class MapRepositoryFaultTolerantStepFactoryBeanTests { private JobRepository repository; - @Autowired - private PlatformTransactionManager transactionManager; + private PlatformTransactionManager transactionManager = new ResourcelessTransactionManager(); @Before public void setUp() throws Exception { - repository = new MapJobRepositoryFactoryBean().getJobRepository(); - reader = new SkipReaderStub(); writer = new SkipWriterStub(); processor = new SkipProcessorStub(); @@ -75,7 +67,6 @@ public class MapRepositoryFaultTolerantStepFactoryBeanTests { factory.setBeanName("stepName"); factory.setTransactionManager(transactionManager); - factory.setJobRepository(repository); factory.setCommitInterval(3); ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(3); @@ -107,7 +98,7 @@ public class MapRepositoryFaultTolerantStepFactoryBeanTests { if (i%100==0) { logger.info("Starting step: "+i); - repository = new MapJobRepositoryFactoryBean().getJobRepository(); + repository = new MapJobRepositoryFactoryBean(transactionManager).getJobRepository(); factory.setJobRepository(repository); jobExecution = repository.createJobExecution("vanillaJob", new JobParameters()); } diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/step/SplitJobMapRepositoryIntegrationTests.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/step/SplitJobMapRepositoryIntegrationTests.java index 4006b947d..47a0e1dc4 100644 --- a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/step/SplitJobMapRepositoryIntegrationTests.java +++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/step/SplitJobMapRepositoryIntegrationTests.java @@ -51,11 +51,16 @@ public class SplitJobMapRepositoryIntegrationTests { JobLauncher jobLauncher = null; Job job = null; + ClassPathXmlApplicationContext context = null; + for (int i = 0; i < MAX_COUNT; i++) { if (i % 100 == 0) { + if (context!=null) { + context.close(); + } logger.info("Starting job: " + i); - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(getClass().getSimpleName() + context = new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass()); jobLauncher = (JobLauncher) context.getBean("jobLauncher", JobLauncher.class); job = (Job) context.getBean("job", Job.class); diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapStepExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapStepExecutionDao.java index d29cc1d1e..1a12a7b30 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapStepExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapStepExecutionDao.java @@ -15,6 +15,7 @@ */ package org.springframework.batch.core.repository.dao; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -29,6 +30,7 @@ import org.springframework.batch.core.StepExecution; import org.springframework.batch.support.SerializationUtils; import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; /** * In-memory implementation of {@link StepExecutionDao}. @@ -49,6 +51,16 @@ public class MapStepExecutionDao implements StepExecutionDao { private static StepExecution copy(StepExecution original) { return (StepExecution) SerializationUtils.deserialize(SerializationUtils.serialize(original)); } + + private static void copy(final StepExecution sourceExecution, final StepExecution targetExecution) { + // Cheaper than full serialization is a reflective field copy, which is fine for volatile storage + ReflectionUtils.doWithFields(StepExecution.class, new ReflectionUtils.FieldCallback() { + public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { + field.setAccessible(true); + field.set(targetExecution, field.get(sourceExecution)); + } + }); + } public void saveStepExecution(StepExecution stepExecution) { @@ -77,7 +89,7 @@ public class MapStepExecutionDao implements StepExecutionDao { Map executions = executionsByJobExecutionId.get(stepExecution.getJobExecutionId()); Assert.notNull(executions, "step executions for given job execution are expected to be already saved"); - StepExecution persistedExecution = executionsByStepExecutionId.get(stepExecution.getId()); + final StepExecution persistedExecution = executionsByStepExecutionId.get(stepExecution.getId()); Assert.notNull(persistedExecution, "step execution is expected to be already saved"); synchronized (stepExecution) { @@ -88,9 +100,8 @@ public class MapStepExecutionDao implements StepExecutionDao { } stepExecution.incrementVersion(); - StepExecution copy = copy(stepExecution); - executions.put(stepExecution.getId(), copy); - executionsByStepExecutionId.put(stepExecution.getId(), copy); + copy(stepExecution, persistedExecution); + executions.put(stepExecution.getId(), persistedExecution); } } diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/transaction/TransactionAwareProxyFactory.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/transaction/TransactionAwareProxyFactory.java index 8901424e5..9e78c7efd 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/transaction/TransactionAwareProxyFactory.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/transaction/TransactionAwareProxyFactory.java @@ -74,7 +74,7 @@ public class TransactionAwareProxyFactory { private TransactionAwareProxyFactory(T target, boolean appendOnly) { super(); - this.target = begin(target); + this.target = target; this.appendOnly = appendOnly; }