-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Simplify configuring transactionManager with Java config #415
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simplify configuring transactionManager with Java config #415
Conversation
I have signed and agree to the terms of the SpringSource Individual Contributor License Agreement. |
This PR won't work as currently coded. Using the getters in the |
Actually, there's no need for me to override the Since One option would have been to add a setter for This PR was an attempt at being as flexible as possible. If you have an idea of a more correct approach, I'm willing to contribute. |
090ae31
to
81a34fb
Compare
81a34fb
to
6a5de97
Compare
How about this instead? KISS - removing the need to subclass for the |
@mminella Any chance to get this into the next version? |
@mjiderhamn The plan for Batch 3.1 (which will begin development in earnest in a couple weeks) is to simplify the java config story across the framework. I'll be sure to consider this use case in some capacity then. FYI, it's targeted to be released in early December. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs some tests to validate the behavior. Otherwise this looks good.
|
||
protected DataSource getDataSource() { | ||
return dataSource; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't needed and should be removed.
If I understand correctly, the idea is that if I provide a transaction manager in my context, it would be used by Spring Batch thanks to autowiring via the new setter added in this PR. This won't work as coded in this PR when I don't specify a bean of type import javax.sql.DataSource;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.aop.Advisor;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.Advised;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.TransactionInterceptor;
@RunWith(MockitoJUnitRunner.class)
public class TransactionManagerConfigTests {
@Mock
protected static PlatformTransactionManager transactionManager;
@Test
public void testConfigurationWithCustomTransactionManager() throws Exception {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BatchConfiguration.class);
PlatformTransactionManager platformTransactionManager = applicationContext.getBean(PlatformTransactionManager.class);
Assert.assertSame(transactionManager, platformTransactionManager);
assertThatTransactionManagerIsSetOnJobRepository(applicationContext, transactionManager);
}
@EnableBatchProcessing
public static class BatchConfiguration {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.addScript("classpath:org/springframework/batch/core/schema-drop-hsqldb.sql")
.addScript("classpath:org/springframework/batch/core/schema-hsqldb.sql")
.build();
}
@Bean
public PlatformTransactionManager transactionManager() {
return transactionManager;
}
}
/*
* The transaction manager set on JobRepositoryFactoryBean in DefaultBatchConfigurer.createJobRepository
* ends up in the TransactionInterceptor advise applied to the (proxied) JobRepository.
* This method extracts the advise from the proxy and checks if the supplied
* transaction manager is the one used by the TransactionInterceptor advise.
*/
private void assertThatTransactionManagerIsSetOnJobRepository(AnnotationConfigApplicationContext applicationContext, PlatformTransactionManager transactionManager) throws Exception {
JobRepository jobRepository = applicationContext.getBean(JobRepository.class);
TargetSource targetSource = ((Advised) jobRepository).getTargetSource(); // proxy created in SimpleBatchConfiguration.createLazyProxy
Advised target = (Advised) targetSource.getTarget(); // initial proxy created in AbstractJobRepositoryFactoryBean.initializeProxy
Advisor[] advisors = target.getAdvisors();
for (Advisor advisor : advisors) {
if (advisor.getAdvice() instanceof TransactionInterceptor) {
TransactionInterceptor transactionInterceptor = (TransactionInterceptor) advisor.getAdvice();
Assert.assertEquals(transactionManager, transactionInterceptor.getTransactionManager());
}
}
}
} This test fails because it is expected that my custom transaction manager is used in the job repository, but a if(this.transactionManager == null) {
this.transactionManager = new DataSourceTransactionManager(dataSource);
} is true even if I have defined a transaction manager in my context and which is supposed to be autowired by the new setter. I think the transaction manager should not be autowired. If the user wants to use a custom transaction manager, he has to provide a custom |
Simplify subclassing
DefaultBatchConfigurer
by just overridinggetTransactionManager()
andgetDataSource()
.