[SPRING] 스프링 - 배치 관리자와 스프링 부트를 적절하게 통합 할 수있는 방법이 있습니까?
SPRING스프링 - 배치 관리자와 스프링 부트를 적절하게 통합 할 수있는 방법이 있습니까?
문서 스프링 배치 관리에 따르면 기존 응용 프로그램에 포함하기가 매우 쉽습니다. web.xml과 index.jsp를 복사하고 필요한 종속성을 추가하기 만하면됩니다.
하지만 기존의 스프링 부트 프로젝트에서 사용하고 싶다면 점점 더 악화되고 있습니다. 이 예제에 따르면 구성은 약간 해킹되지만 작동합니다. 내 configuriton bean에서 @EnableBatchProcessing 어노테이션을 사용하려고 시도 할 때까지. 그렇다면 다음과 같은 예외가 있습니다.
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
내 구성은 매우 간단합니다. 두 개의 구성 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 무료 구성을 preffer 것입니다. 스프링 부트, 스프링 배치 및 스프링 배치 관리를 쉽게 통합 할 수있는 방법이 있습니까?
해결법
-
==============================
1.간단히 말해 Spring Batch Admin에서 @EnableBatchProcessing을 사용하고 싶지 않을 것입니다. SBA는 @EnableBatchProcessing도 제공하는 전역 규모의 여러 가지 빈을 제공합니다. SBA 2.0 (현재 개발 중)은 현재 존재하는 것과 @EnableBatchProcessing이 제공하는 것 (특히 JobBuilderFactory 및 StepBuilderFactory 제공) 사이의 차이를 채울 것입니다.
간단히 말해 Spring Batch Admin에서 @EnableBatchProcessing을 사용하고 싶지 않을 것입니다. SBA는 @EnableBatchProcessing도 제공하는 전역 규모의 여러 가지 빈을 제공합니다. SBA 2.0 (현재 개발 중)은 현재 존재하는 것과 @EnableBatchProcessing이 제공하는 것 (특히 JobBuilderFactory 및 StepBuilderFactory 제공) 사이의 차이를 채울 것입니다.
스스로 실행하려면 META-INF / spring / batch / override / 디렉토리에 JobBuilderFactory와 StepBuilderFactory를 전역 적으로 사용할 수 있도록 구성해야합니다. 거기에서 @Configuration 클래스에 대한 구성 요소 검사 이상의 작업을 수행하는 META-INF / spring / batch / jobs 디렉토리의 XML 파일을 사용할 수 있습니다. 그러나 Bean의 중복 때문에 @EnableBatchProcessing을 사용하지 마십시오.
기록을 위해, @EnableBatchProcessing은 Spring 배치 주석이 아니고 Boot 태그가 아니기 때문에 이것은 Spring Boot 문제가 아닙니다.
-
==============================
2.대답을 완료하려면 @EnableBatchProcessing 주석을 사용하지 않도록 설정 한 후 두 개의 빈을 만드는 코드를 작성하십시오.
대답을 완료하려면 @EnableBatchProcessing 주석을 사용하지 않도록 설정 한 후 두 개의 빈을 만드는 코드를 작성하십시오.
@Autowired JobRepository jobRepository; @Autowired PlatformTransactionManager transactionManager; @Bean public JobBuilderFactory jobBuilderFactory() { return new JobBuilderFactory(jobRepository); } @Bean public StepBuilderFactory stepBuilderFactory() { return new StepBuilderFactory(jobRepository, transactionManager); }
-
==============================
3.Spring Batch Admin 2.0 - BUILD-SNAPSHOT은 스프링 부트와 쉽게 통합 할 수있는 새로운 Annoation @EnableBatchAdmin을 소개합니다. 샘플 프로젝트 https://github.com/spring-projects/spring-batch-admin-samples도 있습니다.
Spring Batch Admin 2.0 - BUILD-SNAPSHOT은 스프링 부트와 쉽게 통합 할 수있는 새로운 Annoation @EnableBatchAdmin을 소개합니다. 샘플 프로젝트 https://github.com/spring-projects/spring-batch-admin-samples도 있습니다.
-
==============================
4.나는 여기에 같은 예제 (나는 원래 하나를 포크)를 기반으로 작업 버전을했습니다 : https://github.com/vesperaba/spring-batch-admin-spring-boot.
나는 여기에 같은 예제 (나는 원래 하나를 포크)를 기반으로 작업 버전을했습니다 : https://github.com/vesperaba/spring-batch-admin-spring-boot.
나는 Michael Minella의 조언을 따랐고 SpringBatch 속성 홀더를 커스텀 테마 홀더로 덮어 썼다.
나는 또한 지금 일하고 있는지 확인하기 위해 일자리를 추가했다.
-
==============================
5.이 ClassCastException는 다음에 의해 발생합니다.
이 ClassCastException는 다음에 의해 발생합니다.
로딩
포함하는
이는 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; } }
Spring Batch Admin 프로젝트의 다른 곳에서 참조되는 추상 기본 메뉴에는 하나의 XML 파일도 필요합니다. Spring 자바 설정에서 추상 Bean을 제공 할 수 없기 때문에 필요하다.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="baseMenu" abstract="true"> <property name="prefix" value="#{resourceService.servletPath}" /> </bean> </beans>
Maven 의존성. Maven이 기본 스프링 프레임 워크의 단일 버전 만 가져 왔는지 확인하십시오.
<dependency> <groupId>org.springframework.batch</groupId> <artifactId>spring-batch-admin-manager</artifactId> <version>1.3.1.RELEASE</version> </dependency> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <scope>runtime</scope> <version>1.8.0.10</version> </dependency>
또한 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
business-schedule-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 ) ;
from https://stackoverflow.com/questions/27139100/is-there-a-way-to-integrate-spring-batch-admin-and-spring-boot-properly by cc-by-sa and MIT license