有没有办法正确地集成spring-batch-admin和spring-boot?

根据文档 spring批处理管理员很容易嵌入到现有的应用程序中。 只需复制web.xml和index.jsp,然后添加所需的依赖项即可使其正常工作。

但是,如果我想在现有的春季启动项目中使用它,它会变得更糟。 根据这个例子 ,配置有点hacky但它​​的工作原理。 我尝试在配置bean中使用@EnableBatchProcessing注释。 然后我得到以下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() 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() at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$$EnhancerBySpringCGLIB$$b5c6eb04$$FastClassBySpringCGLIB$$d88bd05f.invoke() 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() 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 

我的配置非常简单我有两个配置bean

 @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 { } 

 @Configuration @EnableBatchProcessing public class BatchImporterConfiguration { } 

当我删除@EnableBatchProcessing并尝试使用JobBuilderFactory创建作业并使用@StepScope注释时,我正在获取其他ClassCastExceptions。

现在我使用基于xml的配置来创建作业,步骤和其他bean。 它运作良好但我实际上会提供xml免费配置。 有没有办法轻松集成弹簧靴,弹簧批和弹簧批管理?

简短的回答是,您不希望在Spring Batch Admin中使用@EnableBatchProcessing 。 SBA在全球范围内提供了许多@EnableBatchProcessing也提供的bean。 SBA 2.0(目前正在开发中)可能填补当前存在的空间和@EnableBatchProcessing提供的空白(特别是提供JobBuilderFactoryStepBuilderFactory )。

为了让自己运行,你应该能够( 我自己还没有厌倦 )在META-INF/spring/batch/override/目录中配置一个JobBuilderFactory和一个StepBuilderFactory供全局使用。 从那里,您可以在META-INF/spring/batch/jobs目录中使用XML文件,这些文件只对@Configuration类进行组件扫描。 但是,由于bean的重复,请不要使用@EnableBatchProcessing

为了记录,这不是Spring Boot问题,因为@EnableBatchProcessing是一个Spring Batch注释,而不是一个Boot。

Spring Batch Admin 2.0-BUILD-SNAPSHOT引入了一个新的Annoation @EnableBatchAdmin ,便于与spring boot集成。 还有一个示例项目https://github.com/spring-projects/spring-batch-admin-samples 。

要完成答案,这里是禁用@EnableBatchProcessing注释后创建两个bean的代码

 @Autowired JobRepository jobRepository; @Autowired PlatformTransactionManager transactionManager; @Bean public JobBuilderFactory jobBuilderFactory() { return new JobBuilderFactory(jobRepository); } @Bean public StepBuilderFactory stepBuilderFactory() { return new StepBuilderFactory(jobRepository, transactionManager); } 

我在这里有一个基于相同示例的工作版本(我分叉了原始版本): https : //github.com/vesperaba/spring-batch-admin-spring-boot 。

我遵循了Michael Minella的建议,并用自定义的覆盖了SpringBatch属性持有者。

我还添加了一份工作来检查它现在是否正常工作

此ClassCastException是由

classpath:/org/springframework/batch/admin/web/resources/servlet-config.xml

装载

META-INF/spring/batch/servlet/resources/resource-context.xml

其中包含

这与Spring Java配置类中的mvc配置冲突。 以下类可用于在使用Java配置的现有应用程序中嵌入Spring Batch Admin。

 @Configuration @EnableWebMvc @ImportResource({"classpath*:/META-INF/spring/batch/bootstrap/**/*.xml" , "classpath*:/META-INF/spring/batch/override/**/*.xml" , "classpath*:/org/springframework/batch/admin/web/resources/webapp-config.xml" , "classpath*:/META-INF/spring/batch/servlet/manager/**/*.xml" , "classpath:base-menu-config.xml" }) public class SpringBatchAdminConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(final ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/META-INF/"); } @Bean public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() { return new SimpleControllerHandlerAdapter(); } @Bean public BeanNameUrlHandlerMapping beanNameUrlHandlerMapping() { return new BeanNameUrlHandlerMapping(); } @Bean public BeanNameViewResolver beanNameViewResolver() { return new BeanNameViewResolver(); } @Bean(name = "defaultResources") public PropertiesFactoryBean defaultResources() { return new PropertiesFactoryBean(); } @Bean(name = "jsonResources") public PropertiesFactoryBean jsonResources() { return new PropertiesFactoryBean(); } @Bean public HomeController homeController() throws IOException { HomeController homeController = new HomeController(); homeController.setDefaultResources(defaultResources().getObject()); homeController.setJsonResources(jsonResources().getObject()); return homeController; } @Bean public MenuManager menuManager() { return new MenuManager(); } @Bean(name = "freemarkerConfig") public HippyFreeMarkerConfigurer hippyFreeMarkerConfigurer() { HippyFreeMarkerConfigurer hippyFreeMarkerConfigurer = new HippyFreeMarkerConfigurer(); hippyFreeMarkerConfigurer.setTemplateLoaderPaths("/WEB-INF/web", "classpath:/org/springframework/batch/admin/web"); hippyFreeMarkerConfigurer.setPreferFileSystemAccess(false); hippyFreeMarkerConfigurer.setFreemarkerVariables(Collections.singletonMap("menuManager", (Object) menuManager())); Properties freemarkerSettings = new Properties(); freemarkerSettings.put("default_encoding", "UTF-8"); freemarkerSettings.put("output_encoding", "UTF-8"); hippyFreeMarkerConfigurer.setFreemarkerSettings(freemarkerSettings); return hippyFreeMarkerConfigurer; } public AjaxFreeMarkerView parentLayout() { AjaxFreeMarkerView ajaxFreeMarkerView = new AjaxFreeMarkerView(); FreeMarkerViewResolver freeMarkerViewResolver = new FreeMarkerViewResolver(); freeMarkerViewResolver.setExposeSpringMacroHelpers(false); freeMarkerViewResolver.setAllowRequestOverride(true); ajaxFreeMarkerView.setViewResolver(freeMarkerViewResolver); Properties attributes = new Properties(); attributes.put("titleCode", "home.title"); attributes.put("titleText", "Spring Batch Admin"); ajaxFreeMarkerView.setAttributes(attributes); return ajaxFreeMarkerView; } @Value("#{resourceService.servletPath}") private String servletPath; @Bean(name="standard") public AjaxFreeMarkerView standard() { AjaxFreeMarkerView standard = parentLayout(); standard.setUrl("/layouts/html/standard.ftl"); standard.setContentType("text/html;charset=UTF-8"); standard.getAttributesMap().put("body", "/layouts/html/home.ftl"); standard.getAttributesMap().put("servletPath", servletPath); return standard; } @Bean(name="standard.rss") public AjaxFreeMarkerView standardRss() { AjaxFreeMarkerView standardRss = parentLayout(); standardRss.setUrl("/layouts/html/standard.ftl"); standardRss.setContentType("text/xml"); standardRss.getAttributesMap().put("body", "/layouts/rss/home.ftl"); standardRss.getAttributesMap().put("servletPath", servletPath); return standardRss; } @Bean(name="standard.json") public AjaxFreeMarkerView standardJson() { AjaxFreeMarkerView standardJson = parentLayout(); standardJson.setUrl("/layouts/json/standard.ftl"); standardJson.setContentType("application/json"); standardJson.getAttributesMap().put("body", "/layouts/json/home.ftl"); standardJson.getAttributesMap().put("servletPath", servletPath); return standardJson; } @Bean(name="home") public AjaxFreeMarkerView home() { return standard(); } @Bean(name="home.json") public AjaxFreeMarkerView homeJson() { AjaxFreeMarkerView homeJson = standardJson(); homeJson.getAttributesMap().put("body", "/layouts/json/home.ftl"); return homeJson; } } 

抽象基本菜单也需要单个XML文件,该菜单在Spring Batch Admin项目的其他位置引用。 这是必需的,因为无法从Spring Java配置提供抽象bean。

       

Maven依赖。 注意确保Maven只提供单个版本的基本Spring框架。

  org.springframework.batch spring-batch-admin-manager 1.3.1.RELEASE   hsqldb hsqldb runtime 1.8.0.10  

Spring批处理还期望在以下文件的默认配置中存在于类路径的根目录中。

batch-default.properties

 # Default placeholders for database platform independent features batch.remote.base.url=http://localhost:8080/spring-batch-admin-sample # Non-platform dependent settings that you might like to change batch.job.configuration.file.dir=/tmp/config build.artifactId=1 build.version=1 build.buildNumber=1 build.timestamp=1 log.enableConsole=true 

batch-hsql.properties

 # Placeholders batch.* # for HSQLDB: batch.jdbc.driver=org.hsqldb.jdbcDriver batch.jdbc.url=jdbc:hsqldb:mem:testdb;sql.enforce_strict_size=true # Override and use this one in for a separate server process so you can inspect # the results (or add it to system properties with -D to override at run time). # batch.jdbc.url=jdbc:hsqldb:hsql://localhost:9005/samples batch.jdbc.user=sa batch.jdbc.password= batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.HsqlMaxValueIncrementer batch.schema.script=classpath*:/org/springframework/batch/core/schema-hsqldb.sql batch.drop.script=classpath*:/org/springframework/batch/core/schema-drop-hsqldb.sql batch.business.schema.script=classpath:/business-schema-hsqldb.sql # Non-platform dependent settings that you might like to change # batch.data.source.init=true 

业务时间表hsqldb.sql

 DROP TABLE ERROR_LOG IF EXISTS; CREATE TABLE ERROR_LOG ( JOB_NAME CHAR(20) , STEP_NAME CHAR(20) , MESSAGE VARCHAR(300) NOT NULL ) ;