GVKun编程网logo

Spring-Batch:如何从StepListener返回自定义Job退出代码(spring 返回文件)

22

本篇文章给大家谈谈Spring-Batch:如何从StepListener返回自定义Job退出代码,以及spring返回文件的知识点,同时本文还将给你拓展2.1SpringBoot启动流程-Sprin

本篇文章给大家谈谈Spring-Batch:如何从StepListener返回自定义Job退出代码,以及spring 返回文件的知识点,同时本文还将给你拓展2. 1 SpringBoot 启动流程 - SpringApplicationRunListener-Listener 初始化、ContextLoaderListener 和 Spring MVC 中的 DispatcherServlet 加载、ElastciJobListener && AbstractDistributeOnceElasticJobListener、java – Spring Batch:org.springframework.batch.item.ReaderNotOpenException:读者必须先打开才能读取等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

Spring-Batch:如何从StepListener返回自定义Job退出代码(spring 返回文件)

Spring-Batch:如何从StepListener返回自定义Job退出代码(spring 返回文件)

问题是这样的:我只有一个步骤就能完成一个Spring
Batch作业。此步骤称为多次。如果每次调用它,一切正常(无异常),则作业状态为“已完成”。如果至少在Step的执行之一中发生了问题(抛出异常),我已经配置了一个StepListener,它将退出代码更改为FAILED:

public class SkipCheckingListener extends StepExecutionListenerSupport {    public ExitStatus afterStep(StepExecution stepExecution) {        String exitCode = stepExecution.getExitStatus().getExitCode();        if (stepExecution.getProcessorSkipCount() > 0) {            return new ExitStatus(ExitStatus.FAILED);        }        else {            return null;        }    }}

当满足条件时,将执行“ if”块,并且作业以FAILED状态结束,这可以正常工作。但是请注意,我在这里返回的退出代码仍在Spring
Batch随附的标准代码中。我想在某些时候返回我的个性化退出代码,例如“ COMPLETED WITH SKIPS”。现在,我尝试更新上面的代码以返回:

public class SkipCheckingListener extends StepExecutionListenerSupport {    public ExitStatus afterStep(StepExecution stepExecution) {        String exitCode = stepExecution.getExitStatus().getExitCode();        if (stepExecution.getProcessorSkipCount() > 0) {            return new ExitStatus("COMPLETED WITH SKIPS");        }        else {            return null;        }    }}

如文档中所述:http ://static.springsource.org/spring-
batch/reference/html/configureStep.html(5.3.2.1。批处理状态与退出状态)。我什至尝试过

stepExecution.getJobExecution().setExitStatus("COMPLETED WITH SKIPS");

可以肯定的是,执行到达了“ if”块,执行了代码,但我的工作仍然以退出代码COMPLETED完成,完全忽略了我通过侦听器设置的退出代码。

他们的文档中没有关于此的更多详细信息,而且我还没有使用Google找到任何东西。有人可以告诉我如何以这种方式更改Job退出代码吗?谢谢

答案1

小编典典

看起来您只是不能更改BatchStatus,但是可以使用exitstatus尝试

此代码与JobListener对我有用

// JobListener with interface or annotationpublic void afterJob(JobExecution jobExecution) {    jobExecution.setExitStatus(new ExitStatus("foo", "fooBar"));}

2. 1 SpringBoot 启动流程 - SpringApplicationRunListener-Listener 初始化

2. 1 SpringBoot 启动流程 - SpringApplicationRunListener-Listener 初始化

返回 SpringApplication 初始化类可以看到这么一句

this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));

getSpringFactoriesInstances

 private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
        return this.getSpringFactoriesInstances(type, new Class[0]);
    }
 private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = this.getClassLoader();
        Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

SpringFactoriesLoader

这是一个普通的类 属性有下面三个

    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
    private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap();

看到了一个不得了的文件 META-INF/spring.factories,这个文件非常非常重要 很多配置都在这里

spring.factories

看看 springboot 源码里这个文件里都有啥吧

# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor

# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer

# FailureAnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

这么一堆 各种熟悉的名词都在这 SpringApplicationRunListener、ApplicationContextInitializer、ApplicationListener、PropertySourceLoader

loadFactoryNames(type, classLoader)

 public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryClassName = ((String)entry.getKey()).trim();
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryName = var9[var11];
                            result.add(factoryClassName, factoryName.trim());
                        }
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }

//todo 这个方法暂且不分析了,大体就是从 spring.factories 里根据 key 取 vale 这里涉及到一个概念 SPI(Service provider Interface),具体请看《SpringBoot-SPI 是个什么东东》

内置 Listener

就是文件里这一堆

ContextLoaderListener 和 Spring MVC 中的 DispatcherServlet 加载

ContextLoaderListener 和 Spring MVC 中的 DispatcherServlet 加载

ContextLoaderListener 和 Spring MVC 中的 DispatcherServlet 加载内容的区别

一:ContextLoaderListener 加载内容

  

二:DispatcherServlt 加载内容

  

  ContextLoaderListener 和 DispatcherServlet 都会在 Web 容器启动的时候加载一下 bean 配置。区别在于:

  DispatcherServlet 一般会加载 MVC 相关的 bean 配置管理 (如: ViewResolver, Controller, MultipartResolver, ExceptionHandler, etc.)

  ContextLoaderListener 一般会加载整个 Spring 容器相关的 bean 配置管理 (如: Log, Service, Dao, PropertiesLoader, etc.)

  DispatcherServlet 默认使用 WebApplicationContext 作为上下文.

  值得注意的是,DispatcherServlet 的上下文仅仅是 Spring MVC 的上下文,而 ContextLoaderListener 的上下文则对整个 Spring 都有效。一般 Spring web 项目中同时会使用这两种上下文.

ElastciJobListener && AbstractDistributeOnceElasticJobListener

ElastciJobListener && AbstractDistributeOnceElasticJobListener

esjob监听器的作用是什么?该怎么实现?有没有demo

java – Spring Batch:org.springframework.batch.item.ReaderNotOpenException:读者必须先打开才能读取

java – Spring Batch:org.springframework.batch.item.ReaderNotOpenException:读者必须先打开才能读取

我读了相关的问题,但解决方案对我来说并不奏效.

我得到了org.springframework.batch.item.ReaderNotOpenException:读者必须打开才能读取异常.

以下是我的配置:

@Bean
@StepScope
public ItemReader<Player> reader(@Value("#{jobParameters[inputZipfile]}") String inputZipfile) {
                final String [] header = { .. this part omitted for brevity ... };
                FlatFileItemReader<Player> reader = new FlatFileItemReader<Player>();


                System.out.println("\t\t\t\t\t"+inputZipfile);

                reader.setResource(new ClassPathResource(inputZipfile));
                reader.setLineMapper(new DefaultLineMapper<Player>() {{
                    setLinetokenizer(new DelimitedLinetokenizer() {{
                        setNames( header );
                    }});
                    setFieldSetMapper(new BeanWrapperFieldSetMapper<Player>() {{
                        settargettype(Player.class);
                    }});
                }});
                reader.setComments( header );
                return reader;
}

@Bean
@StepScope
public itemprocessor<Player,PlayeRSStats> processor(@Value("#{jobParameters[statType]}") String statType,@Value("#{jobParameters[season]}") String season){
                PlayeRSStatsProcessor psp = new PlayeRSStatsProcessor();
                psp.setStatisticType( StatisticType.valueOf(statType) );
                psp.setSeason( season );
                return psp;
}


@Bean
@StepScope
public ItemWriter<PlayeRSStats> writer(){
            return new CustomWriter();
}


@Bean
public Job generateStatisticsJob() {

        return this.jobs.get("generateStatisticsJob")
                .incrementer(new RunIdIncrementer())
                .start(processplayerStats())
                //.end()
                .build();
}

@Bean
public Step processplayerStats() {
           return this.steps.get("processplayerStats")        
                        .<Player,PlayeRSStats> chunk(10)
                        .reader(reader(null))
                        .processor(processor(null,null))
                        .writer(writer())
                        .build();
}

inputZipFile变量设置正确,文件存在于驱动器上.
我检查了FlatFileItemReader代码,并且ReaderNotOpenException发生在读者类的读者成员未设置时.读者成员设置为doOpen方法.
看起来doOpen不被调用.问题是为什么?

解决方法

当我将读取器bean的返回类型从Item更改为FlatFileItemReader时,问题消失了.我仍然不清楚为什么这是一个问题,因为chunk().reader()接受ItemReader作为输入.我假设有一些AOP魔术在引擎盖下,FlatFileReader init和返回类型匹配.

今天关于Spring-Batch:如何从StepListener返回自定义Job退出代码spring 返回文件的分享就到这里,希望大家有所收获,若想了解更多关于2. 1 SpringBoot 启动流程 - SpringApplicationRunListener-Listener 初始化、ContextLoaderListener 和 Spring MVC 中的 DispatcherServlet 加载、ElastciJobListener && AbstractDistributeOnceElasticJobListener、java – Spring Batch:org.springframework.batch.item.ReaderNotOpenException:读者必须先打开才能读取等相关知识,可以在本站进行查询。

本文标签: