Add transaction support in JobExplorerFactoryBean
This commit adds support to create a transactional proxy around the JobExplorer created by the JobExplorerFactoryBean. Resolves #1307
This commit is contained in:
@@ -136,6 +136,9 @@ class BatchRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
String dataSourceRef = batchAnnotation.dataSourceRef();
|
||||
beanDefinitionBuilder.addPropertyReference("dataSource", dataSourceRef);
|
||||
|
||||
String transactionManagerRef = batchAnnotation.transactionManagerRef();
|
||||
beanDefinitionBuilder.addPropertyReference("transactionManager", transactionManagerRef);
|
||||
|
||||
// set optional properties
|
||||
String executionContextSerializerRef = batchAnnotation.executionContextSerializerRef();
|
||||
if (registry.containsBeanDefinition(executionContextSerializerRef)) {
|
||||
|
||||
@@ -157,6 +157,7 @@ public class DefaultBatchConfiguration implements ApplicationContextAware {
|
||||
public JobExplorer jobExplorer() throws BatchConfigurationException {
|
||||
JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean();
|
||||
jobExplorerFactoryBean.setDataSource(getDataSource());
|
||||
jobExplorerFactoryBean.setTransactionManager(getTransactionManager());
|
||||
jobExplorerFactoryBean.setJdbcOperations(getJdbcOperations());
|
||||
jobExplorerFactoryBean.setCharset(getCharset());
|
||||
jobExplorerFactoryBean.setTablePrefix(getTablePrefix());
|
||||
|
||||
@@ -16,12 +16,23 @@
|
||||
|
||||
package org.springframework.batch.core.explore.support;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.batch.core.explore.JobExplorer;
|
||||
import org.springframework.batch.core.repository.dao.ExecutionContextDao;
|
||||
import org.springframework.batch.core.repository.dao.JobExecutionDao;
|
||||
import org.springframework.batch.core.repository.dao.JobInstanceDao;
|
||||
import org.springframework.batch.core.repository.dao.StepExecutionDao;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionManager;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
|
||||
import org.springframework.transaction.interceptor.TransactionInterceptor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link FactoryBean} that automates the creation of a {@link SimpleJobExplorer}. It
|
||||
@@ -32,7 +43,15 @@ import org.springframework.beans.factory.FactoryBean;
|
||||
* @author Mahmoud Ben Hassine
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AbstractJobExplorerFactoryBean implements FactoryBean<JobExplorer> {
|
||||
public abstract class AbstractJobExplorerFactoryBean implements FactoryBean<JobExplorer>, InitializingBean {
|
||||
|
||||
private static final String TRANSACTION_ISOLATION_LEVEL_PREFIX = "ISOLATION_";
|
||||
|
||||
private static final String TRANSACTION_PROPAGATION_PREFIX = "PROPAGATION_";
|
||||
|
||||
private PlatformTransactionManager transactionManager;
|
||||
|
||||
private ProxyFactory proxyFactory = new ProxyFactory();
|
||||
|
||||
/**
|
||||
* Creates a job instance data access object (DAO).
|
||||
@@ -62,6 +81,30 @@ public abstract class AbstractJobExplorerFactoryBean implements FactoryBean<JobE
|
||||
*/
|
||||
protected abstract ExecutionContextDao createExecutionContextDao() throws Exception;
|
||||
|
||||
/**
|
||||
* Public setter for the {@link PlatformTransactionManager}.
|
||||
* @param transactionManager the transactionManager to set
|
||||
* @since 5.0
|
||||
*/
|
||||
public void setTransactionManager(PlatformTransactionManager transactionManager) {
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* The transaction manager used in this factory. Useful to inject into steps and jobs,
|
||||
* to ensure that they are using the same instance.
|
||||
* @return the transactionManager
|
||||
* @since 5.0
|
||||
*/
|
||||
public PlatformTransactionManager getTransactionManager() {
|
||||
return this.transactionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(this.transactionManager, "TransactionManager must not be null.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of object to be returned from {@link #getObject()}.
|
||||
* @return {@code JobExplorer.class}
|
||||
@@ -77,4 +120,27 @@ public abstract class AbstractJobExplorerFactoryBean implements FactoryBean<JobE
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JobExplorer getObject() throws Exception {
|
||||
Properties transactionAttributes = new Properties();
|
||||
String transactionProperties = String.join(",", TRANSACTION_PROPAGATION_PREFIX + Propagation.SUPPORTS,
|
||||
TRANSACTION_ISOLATION_LEVEL_PREFIX + Isolation.READ_COMMITTED);
|
||||
transactionAttributes.setProperty("get*", transactionProperties);
|
||||
transactionAttributes.setProperty("find*", transactionProperties);
|
||||
NameMatchTransactionAttributeSource transactionAttributeSource = new NameMatchTransactionAttributeSource();
|
||||
transactionAttributeSource.setProperties(transactionAttributes);
|
||||
TransactionInterceptor advice = new TransactionInterceptor((TransactionManager) transactionManager,
|
||||
transactionAttributeSource);
|
||||
proxyFactory.addAdvice(advice);
|
||||
proxyFactory.setProxyTargetClass(false);
|
||||
proxyFactory.addInterface(JobExplorer.class);
|
||||
proxyFactory.setTarget(getTarget());
|
||||
return (JobExplorer) proxyFactory.getProxy(getClass().getClassLoader());
|
||||
}
|
||||
|
||||
private JobExplorer getTarget() throws Exception {
|
||||
return new SimpleJobExplorer(createJobInstanceDao(), createJobExecutionDao(), createStepExecutionDao(),
|
||||
createExecutionContextDao());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -147,11 +147,8 @@ public class JobExplorerFactoryBean extends AbstractJobExplorerFactoryBean imple
|
||||
if (serializer == null) {
|
||||
serializer = new Jackson2ExecutionContextStringSerializer();
|
||||
}
|
||||
}
|
||||
|
||||
private JobExplorer getTarget() throws Exception {
|
||||
return new SimpleJobExplorer(createJobInstanceDao(), createJobExecutionDao(), createStepExecutionDao(),
|
||||
createExecutionContextDao());
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -196,9 +193,4 @@ public class JobExplorerFactoryBean extends AbstractJobExplorerFactoryBean imple
|
||||
return dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JobExplorer getObject() throws Exception {
|
||||
return getTarget();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,10 +29,12 @@ import org.springframework.batch.core.explore.JobExplorer;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Will Schipp
|
||||
* @author Mahmoud Ben Hassine
|
||||
*
|
||||
*/
|
||||
class JobExplorerFactoryBeanTests {
|
||||
@@ -46,7 +48,9 @@ class JobExplorerFactoryBeanTests {
|
||||
|
||||
factory = new JobExplorerFactoryBean();
|
||||
DataSource dataSource = mock(DataSource.class);
|
||||
PlatformTransactionManager transactionManager = mock(PlatformTransactionManager.class);
|
||||
factory.setDataSource(dataSource);
|
||||
factory.setTransactionManager(transactionManager);
|
||||
factory.setTablePrefix(tablePrefix);
|
||||
|
||||
}
|
||||
@@ -78,6 +82,16 @@ class JobExplorerFactoryBeanTests {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMissingTransactionManager() {
|
||||
|
||||
factory.setTransactionManager(null);
|
||||
Exception exception = assertThrows(IllegalArgumentException.class, factory::afterPropertiesSet);
|
||||
String message = exception.getMessage();
|
||||
assertTrue(message.contains("TransactionManager"), "Wrong message: " + message);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateExplorer() throws Exception {
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ class SimpleJobExplorerIntegrationTests {
|
||||
public JobExplorerFactoryBean jobExplorerFactoryBean() {
|
||||
JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean();
|
||||
jobExplorerFactoryBean.setDataSource(dataSource());
|
||||
jobExplorerFactoryBean.setTransactionManager(transactionManager(dataSource()));
|
||||
return jobExplorerFactoryBean;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@ class SimpleJobTests {
|
||||
this.jobRepository = repositoryFactoryBean.getObject();
|
||||
JobExplorerFactoryBean explorerFactoryBean = new JobExplorerFactoryBean();
|
||||
explorerFactoryBean.setDataSource(embeddedDatabase);
|
||||
explorerFactoryBean.setTransactionManager(transactionManager);
|
||||
explorerFactoryBean.afterPropertiesSet();
|
||||
this.jobExplorer = explorerFactoryBean.getObject();
|
||||
job = new SimpleJob();
|
||||
|
||||
@@ -76,9 +76,10 @@ public class FlowJobTests {
|
||||
EmbeddedDatabase embeddedDatabase = new EmbeddedDatabaseBuilder()
|
||||
.addScript("/org/springframework/batch/core/schema-drop-hsqldb.sql")
|
||||
.addScript("/org/springframework/batch/core/schema-hsqldb.sql").build();
|
||||
JdbcTransactionManager transactionManager = new JdbcTransactionManager(embeddedDatabase);
|
||||
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
|
||||
factory.setDataSource(embeddedDatabase);
|
||||
factory.setTransactionManager(new JdbcTransactionManager(embeddedDatabase));
|
||||
factory.setTransactionManager(transactionManager);
|
||||
factory.afterPropertiesSet();
|
||||
this.jobRepository = factory.getObject();
|
||||
job.setJobRepository(this.jobRepository);
|
||||
@@ -86,6 +87,7 @@ public class FlowJobTests {
|
||||
|
||||
JobExplorerFactoryBean explorerFactoryBean = new JobExplorerFactoryBean();
|
||||
explorerFactoryBean.setDataSource(embeddedDatabase);
|
||||
explorerFactoryBean.setTransactionManager(transactionManager);
|
||||
explorerFactoryBean.afterPropertiesSet();
|
||||
this.jobExplorer = explorerFactoryBean.getObject();
|
||||
}
|
||||
|
||||
@@ -53,13 +53,15 @@ class RemoteStepExecutionAggregatorTests {
|
||||
EmbeddedDatabase embeddedDatabase = new EmbeddedDatabaseBuilder()
|
||||
.addScript("/org/springframework/batch/core/schema-drop-hsqldb.sql")
|
||||
.addScript("/org/springframework/batch/core/schema-hsqldb.sql").build();
|
||||
JdbcTransactionManager transactionManager = new JdbcTransactionManager(embeddedDatabase);
|
||||
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
|
||||
factory.setDataSource(embeddedDatabase);
|
||||
factory.setTransactionManager(new JdbcTransactionManager(embeddedDatabase));
|
||||
factory.setTransactionManager(transactionManager);
|
||||
factory.afterPropertiesSet();
|
||||
JobRepository jobRepository = factory.getObject();
|
||||
JobExplorerFactoryBean explorerFactoryBean = new JobExplorerFactoryBean();
|
||||
explorerFactoryBean.setDataSource(embeddedDatabase);
|
||||
explorerFactoryBean.setTransactionManager(transactionManager);
|
||||
explorerFactoryBean.afterPropertiesSet();
|
||||
aggregator.setJobExplorer(explorerFactoryBean.getObject());
|
||||
jobExecution = jobRepository.createJobExecution("job", new JobParameters());
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
<bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
<property name="transactionManager" ref="transactionManager"/>
|
||||
</bean>
|
||||
|
||||
<bean id="tasklet" class="org.springframework.batch.core.configuration.xml.FailingTasklet"/>
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
<beans:bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
|
||||
<beans:property name="dataSource" ref="dataSource"/>
|
||||
<beans:property name="transactionManager" ref="transactionManager"/>
|
||||
</beans:bean>
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
<beans:bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
|
||||
<beans:property name="dataSource" ref="dataSource"/>
|
||||
<beans:property name="transactionManager" ref="transactionManager"/>
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="step1" class="org.springframework.batch.core.step.tasklet.TaskletStep">
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
|
||||
<bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
<property name="transactionManager" ref="transactionManager"/>
|
||||
</bean>
|
||||
|
||||
<bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry"/>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
<beans:bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
|
||||
<beans:property name="dataSource" ref="dataSource"/>
|
||||
<beans:property name="transactionManager" ref="transactionManager"/>
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="jobLauncher" class="org.springframework.batch.core.launch.support.TaskExecutorJobLauncher"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
<bean id="jobExplorer"
|
||||
class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean"
|
||||
p:dataSource-ref="dataSource" />
|
||||
p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager" />
|
||||
|
||||
<bean id="jobRegistry"
|
||||
class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
|
||||
<bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
<property name="transactionManager" ref="transactionManager"/>
|
||||
</bean>
|
||||
|
||||
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.TaskExecutorJobLauncher">
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
<bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
<property name="transactionManager" ref="transactionManager"/>
|
||||
</bean>
|
||||
|
||||
<bean id="simpleJob" class="org.springframework.batch.core.job.SimpleJob" abstract="true">
|
||||
|
||||
@@ -33,11 +33,7 @@
|
||||
<bean id="notificationPublisher" class="org.springframework.batch.sample.jmx.JobExecutionNotificationPublisher" />
|
||||
<bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
|
||||
<bean id="jobOperator" class="org.springframework.batch.core.launch.support.SimpleJobOperator">
|
||||
<property name="jobExplorer">
|
||||
<bean class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
|
||||
<property name="dataSource" ref="dataSource" />
|
||||
</bean>
|
||||
</property>
|
||||
<property name="jobExplorer" ref="jobExplorer"/>
|
||||
<property name="jobRepository" ref="jobRepository" />
|
||||
<property name="jobRegistry" ref="jobRegistry" />
|
||||
<property name="jobLauncher">
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<bean id="jobExplorer"
|
||||
class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean"
|
||||
p:dataSource-ref="dataSource" />
|
||||
p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager"/>
|
||||
|
||||
<bean id="jobRegistry"
|
||||
class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
p:jobExplorer-ref="jobExplorer" p:jobRepository-ref="jobRepository" p:jobRegistry-ref="jobRegistry" />
|
||||
|
||||
<bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean"
|
||||
p:dataSource-ref="dataSource" />
|
||||
p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager"/>
|
||||
|
||||
<bean class="org.springframework.batch.core.configuration.support.AutomaticJobRegistrar">
|
||||
<property name="applicationContextFactories">
|
||||
|
||||
Reference in New Issue
Block a user