According to the documentation spring batch admin is very easy to embed into the existing application. Simply copying web.xml and index.jsp then adding needed dependencies is enough getting it to work.
But if I want to use it in an existing spring boot project it getting worse. According to this example the configuration is a bit hacky but it works. UNTIL I try to use @EnableBatchProcessing
annotation in my configuriton bean. Then I get the following exception.
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jobBuilders' defined in class path resource [org/springframework/batch/core/configuration/annotation/SimpleBatchConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.batch.core.configuration.annotation.JobBuilderFactory org.springframework.batch.core.configuration.annotation.AbstractBatchConfiguration.jobBuilders() throws java.lang.Exception] threw exception; nested exception is java.lang.ClassCastException: org.springframework.batch.core.repository.support.JobRepositoryFactoryBean$$EnhancerBySpringCGLIB$$49fa0273 cannot be cast to org.springframework.batch.core.repository.JobRepository
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:597)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1095)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:990)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
at demo.Application.main(Application.java:35)
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.batch.core.configuration.annotation.JobBuilderFactory org.springframework.batch.core.configuration.annotation.AbstractBatchConfiguration.jobBuilders() throws java.lang.Exception] threw exception; nested exception is java.lang.ClassCastException: org.springframework.batch.core.repository.support.JobRepositoryFactoryBean$$EnhancerBySpringCGLIB$$49fa0273 cannot be cast to org.springframework.batch.core.repository.JobRepository
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:188)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:586)
... 17 more
Caused by: java.lang.ClassCastException: org.springframework.batch.core.repository.support.JobRepositoryFactoryBean$$EnhancerBySpringCGLIB$$49fa0273 cannot be cast to org.springframework.batch.core.repository.JobRepository
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$$EnhancerBySpringCGLIB$$b5c6eb04.jobRepository(<generated>)
at org.springframework.batch.core.configuration.annotation.AbstractBatchConfiguration.jobBuilders(AbstractBatchConfiguration.java:58)
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$$EnhancerBySpringCGLIB$$b5c6eb04.CGLIB$jobBuilders$8(<generated>)
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$$EnhancerBySpringCGLIB$$b5c6eb04$$FastClassBySpringCGLIB$$d88bd05f.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312)
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$$EnhancerBySpringCGLIB$$b5c6eb04.jobBuilders(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
... 18 more
My configuration is quite simple I have two configuration beans
@Configuration
@ImportResource({"classpath:/org/springframework/batch/admin/web/resources/servlet-config.xml",
"classpath:/org/springframework/batch/admin/web/resources/webapp-config.xml"})
public class BatchAdminConfiguration {
}
and
@Configuration
@EnableBatchProcessing
public class BatchImporterConfiguration {
}
When I remove @EnableBatchProcessing and try to create jobs with JobBuilderFactory and use @StepScope annotation I'm getting other ClassCastExceptions.
Now I'm using xml based configuration to create jobs, steps and other beans. It work well but I would actually preffer xml free configuration. Is there a way to easily integrate spring boot, spring batch and spring batch admin ?
Yes you can use Spring Batch without Spring Boot. Spring Batch existed years before Spring Boot came out.
Multiple jobs can be run simultaneously. There are two main types of Spring Batch Parallel Processing: Single Process, Multi-threaded, or Multi-process. These are also divided into subcategories, as follows: Multi-threaded Step (Step with many threads, single process)
spring-batch-integration (part of spring-batch) has components that allow you to launch a batch job from a Spring Integration message flow, as well as components to configure a batch job to distribute work (parts of the batch job) to multiple "worker nodes" using either "remote chunking" or "partitioning".
Spring Batch Admin 2.0-BUILD-SNAPSHOT introduce a new Annoation @EnableBatchAdmin
for easy to integrate with spring boot.
There is also a samples project https://github.com/spring-projects/spring-batch-admin-samples.
to complete the answer, here is the code to create the two beans once you disable the @EnableBatchProcessing annotation
@Autowired
JobRepository jobRepository;
@Autowired
PlatformTransactionManager transactionManager;
@Bean
public JobBuilderFactory jobBuilderFactory() {
return new JobBuilderFactory(jobRepository);
}
@Bean
public StepBuilderFactory stepBuilderFactory() {
return new StepBuilderFactory(jobRepository, transactionManager);
}
The short answer is that you won't want to use @EnableBatchProcessing
with Spring Batch Admin. SBA provides a number of beans on a global scale that the @EnableBatchProcessing
also provides. SBA 2.0 (currently in development) will probably fill the gaps between what is currently there and what @EnableBatchProcessing
provides (specifically providing the JobBuilderFactory
and StepBuilderFactory
).
To get yourself running, you should be able to (I haven't tired this myself) configure in the META-INF/spring/batch/override/
directory a JobBuilderFactory
and a StepBuilderFactory
for global use. From there, you can use XML files in the META-INF/spring/batch/jobs
directory that do nothing more than component scan for your @Configuration
classes. However, leave off the @EnableBatchProcessing
because of the duplication of beans.
For the record, this isn't an Spring Boot issue since @EnableBatchProcessing
is a Spring Batch annotation, not a Boot one.
I've a working version here based on the same example (I forked the original one): https://github.com/vesperaba/spring-batch-admin-spring-boot.
I followed Michael Minella advice and I overwrote the SpringBatch property holder with a custom one.
I also added a job to check it's working now
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With