Reputation: 1842
I've been working for a few days on a Spring Batch (4.3.10) on Spring Cloud Task (2.4.6) all via Spring Boot (2.7.18). I'm going crazy trying to figure out how to configure my application and specifically how auto-configurations works...
What I don't understand is how to properly configure the same TransactionManager
in JOB+TASK repositories.
I currently have this configurations (in summary):
DataSourceConfiguration
@Configuration
public class DataSourceConfiguration {
@BatchDataSource
@Bean
@ConfigurationProperties("batchandtask.datasource")
public DataSource batchDataSource() {
return batchDataSourceProperties().initializeDataSourceBuilder().build();
}
@Bean
public DataSourceProperties batchDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
public TaskConfigurer taskConfigurer() {
return new DefaultTaskConfigurer(batchDataSource());
}
...others DataSource configs
Some notes on this configuration:
@BatchDataSource
annotation because I have another @Primary
DataSource, which I deliberately omitted because it is not strictly related to my doubts.TaskConfigurer
because I want to use the same data source as the batch.JobConfiguration
@Configuration
@EnableBatchProcessing
@EnableTask
public class JobConfiguration {
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
public JobConfiguration(JobBuilderFactory jobBuilderFactory,
StepBuilderFactory stepBuilderFactory) {
this.jobBuilderFactory = jobBuilderFactory;
this.stepBuilderFactory = stepBuilderFactory;
}
... Job and Steps beans
Auto-configurations
From what I saw in the code, the auto-configurations of the task occur before those of the batch and specifically this bean is created during this auto-config:
public class SimpleTaskAutoConfiguration {
...
@Bean
public PlatformTransactionManager springCloudTaskTransactionManager() {
return this.platformTransactionManager;
}
So now I have a TransactionManager
type bean named "springCloudTaskTransactionManager" in the context which is responsible for managing the transactions of the TASK repository. Now I want to configure the same transaction manager for my JOB repository but here I didn't understand how the auto-configurations work. Specifically, I identified that for Spring Batch (unlike Spring Task
) there are two configurators (BatchConfigurer
) implementation:
BasicBatchConfigurer
, that came from org.springframework.boot:spring-boot-autoconfigure:2.7.18 (Spring Boot). Is the one that is actually picked-up in my application and is instantiated as a bean via the BatchAutoConfiguration
auto-config condition @ConditionalOnMissingBean(BatchConfigurer.class)
. This configurator creates his own TransactionManager
that is different from the "springCloudTaskTransactionManager"DefaultBatchConfigurer
, that came from org.springframework.batch:spring-batch-core:4.3.10 (Spring Batch). This is annotated as @Component
but is ignored during the 1. auto-config (i don't understand why) and it is directly instantiated in the absence of a bean of type BatchConfigurer.class
by the @EnableBatchProcessing
annotation. Also in this case he creates his own TransactionManager
.In both cases it is through @EnableBatchProcessing -> SimpleBatchConfiguration
which the TransactionManager
is exposed in the context through this set-up:
@Bean
public PlatformTransactionManager transactionManager() throws Exception {
return createLazyProxy(transactionManager, PlatformTransactionManager.class);
}
where transactionManager it is respectively the one created by one of the two configurators and is qualified as a generic "transactionManager" (problems in sight with other datasource/transactions Spring Boot auto-configurations?)
So after all this magic we have two transactionManagers the one qualified as "springCloudTaskTransactionManager" and the one as "transactionManager".
Questions
I would like to ask for help in understanding some things:
@EnableBatchProcessing
? That there is nothing wrong but why?@EnableBatchProcessing
have some unwanted behavior with Spring Boot, in particular regarding the transactionManager?TransactionManager
for the TASK repository and the JOB repository?Upvotes: 1
Views: 703
Reputation: 3889
Using Spring Cloud Task together with Spring Boot and Spring Batch is probably the most common use case for Spring Cloud Task. But it is not the only supported one.
For example, you can also use just Spring Batch (with or without Spring Boot) or you can use Spring Cloud Task with Spring Boot but without Spring Batch. Each of these possibilities comes with its own bootstrapping facilities, and there are multiple ways how to define the transaction management.
This can indeed be confusing and that's basically why a lot of this has been revamped for Spring Boot 3. But it's all doable with Spring Boot 2.
The annotation @Component
on DefaultBatchConfigurer
doesn't do anything in your case. You should ignore it. @Component
marks classes for auto-scanning but Spring Boot will only scan the packages below your main application class (unless you specify something else). By default, Spring Boot will not auto-scan any dependencies like Spring Batch for bean definitions.
The class SimpleBatchConfiguration
is imported by using @EnableBatchProcessing
. It's method initialize
determines the BatchConfigurer
that will be used: If the application context contains a BatchConfigurer
, then it will be used. Otherwise, a DefaultBatchConfigurer
will be instantiated.
The BasicBatchConfigurer
that you see being used is added to the application context by Spring Boot's BatchConfigurerConfiguration
. This configuration class will expose one of two BatchConfigurer
s depending on whether JPA is on the classpath or not. But BatchConfigurerConfiguration
is annotated with @ConditionalOnMissingBean(BatchConfigurer.class)
, which means that it will back off (and not do anything) if you expose your own BatchConfigurer
.
You need to implement and expose your own BatchConfigurer
and TaskConfigurer
, which set the DataSource
and TransactionManager
as you need.
You'll need your own implementation of BatchConfigurer
and expose it as a bean. It will then be used to set up Spring Batch because Spring Boot's BatchConfigurerConfiguration
will back off.
You can extend either BasicBatchConfigurer
or DefaultBatchConfigurer
, set the DataSource
that you want, and override the method getTransactionManager
to return the transaction manager that you want to use.
With Spring Cloud Task 2.x, you can really only use a transaction manager that is called springCloudTaskTransactionManager
as it is referenced by name. You have two options:
You can use DefaultTaskConfigurer
to set the DataSource
that you want Spring Cloud to use, let it build springCloudTaskTransactionManager
, and then inject this transaction manager into your custom BatchConfigurer
.
Or you can implement your own TaskConfigurer
(e.g. by extending DefaultTaskConfigurer
) to return the transaction manager that you want in getTransactionManager
.
Upvotes: 2