简体   繁体   English

如何在生产环境中运行 spring 批处理中的“作业”

[英]How do you run the `Job` in the spring batch in a production environment

I implemented now with spring batch to manage dormant account.我现在用spring batch来管理休眠帐户。 The following problems occurred while using the spring batch .使用spring batch时出现以下问题。

Spring Batch When I run using joblauncher, I think the job is not running Spring 批处理当我使用 joblauncher 运行时,我认为作业没有运行

The rough content of the article is that the method with @Bean cannot be executed because it is managed as a single tone in the spring .文章的粗略内容是不能执行带有@Bean的方法,因为它在spring中作为单音进行管理。

I wanted to run Job somehow using the @Scheduled and solved it with the following solution.我想以某种方式使用@Scheduled运行Job并使用以下解决方案解决它。

  1. Replace the @Configuration in the batch class I created with @Component .将我创建的批次 class 中的@Configuration替换为@Component
  2. Erase all @Bean on the Job , Step , Reader , Processor , and Writer .擦除JobStepReaderProcessorWriter上的所有@Bean

After doing so, Job worked as I wanted and got a log.这样做之后, Job按照我的意愿工作并得到了一份日志。

I solved the problem, but there was another problem.我解决了这个问题,但还有另一个问题。

In a lot of example, even spring official documents attached @Bean at all of Job.在很多例子中,甚至 spring 官方文件都附有@Bean的所有 Job。

Furthermore, it seemed that JobParameter could not be used without @Bean attached.此外,如果没有附加JobParameter ,似乎无法使用@Bean (When I tried to use the JobParameter , the initial value was null .) (当我尝试使用JobParameter时,初始值为null 。)

I'm going to ask you a real question now.我现在要问你一个真正的问题。

Spring Batch will also be used in the field. Spring Batch也将在现场使用。 And it's expected to put @Bean , as it says in the official document.正如官方文档中所说,预计会放置@Bean So, how do you run a Job in the field?那么,如何在现场运行作业?

Please let me know where I need to fix in my code.请让我知道我需要在我的代码中修复的地方。

package com.capston.chatting.service.scheduler;

import com.capston.chatting.config.batch.InactiveMemberJob;
import com.capston.chatting.entity.Member;
import com.capston.chatting.enums.MemberStatus;
import com.capston.chatting.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.*;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class ScheduleService {

    private final InactiveMemberJob config;
    private final JobLauncher jobLauncher;
    private final MemberRepository memberRepository;
    private final JobExplorer jobExplorer;

    //test

    @Scheduled(cron = "0/5 * * * * *")
    public void runInactiveMemberScheduler() {
        try {
            jobLauncher.run(
                    config.inactiveMemberJob(), new JobParametersBuilder(jobExplorer)
                            .getNextJobParameters(config.inactiveMemberJob())
                            .addString("requestDate", LocalDateTime.now().toString().substring(0, 16))
                            .addString("test", "Test")
                            .toJobParameters()
            );
        } catch(Exception e) {
            log.error(e.getMessage());
        }
    }
}
package com.capston.chatting.config.batch;

import com.capston.chatting.entity.Member;
import com.capston.chatting.enums.MemberStatus;
import com.capston.chatting.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@RequiredArgsConstructor
@Component
public class InactiveMemberJob {

    private final MemberRepository memberRepository;
    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

    public Job inactiveMemberJob() {
        log.info("InactiveMemberJob execution");
        return jobBuilderFactory.get("inactiveMemberJob")
                .start(inactiveJobStep())
                .preventRestart()
                .incrementer(new UniqueRunIdIncrementer())
                .build();
    }

    public Step inactiveJobStep() {
        log.info("InactiveMemberStep execution");
        return stepBuilderFactory.get("inactiveMemberStep")
                .<Member, Member>chunk(10)
                .reader(inactiveMemberReader(null))
                .processor(inactiveMemberProcessor())
                .writer(inactiveMemberWriter())
                .allowStartIfComplete(true)
                .build();
    }

    @StepScope
    public ListItemReader<Member> inactiveMemberReader(@Value("#{jobparameters[test]}") String test) {
        log.info("InactiveMemberReader execution");
        log.info("JobParameters : {}", test);

        List<Member> oldMembers = memberRepository
                .findByUpdateDateBeforeAndStatusEquals(LocalDateTime.now().minusYears(1), MemberStatus.ACTIVE);

        return new ListItemReader<>(oldMembers);
    }

    public ItemProcessor<Member, Member> inactiveMemberProcessor() {
        log.info("test");
        ItemProcessor<Member, Member> memberItemProcessor = (member) -> {
            log.info("InactiveMemberProcessor execution");
            return member.setInactive();
        };
        return memberItemProcessor;
//        return new ItemProcessor<Member, Member>() {
//            @Override
//            public Member process(Member member) throws Exception {
//                log.info("InactiveMemberProcessor execution");
//                return member.setInactive();
//            }
//        };
//        return member -> {
//            log.info("InactiveMemberProcessor execution");
//            return member.setInactive();
//        };
    }

    public ItemWriter<Member> inactiveMemberWriter() {
        log.info("InactiveMemberWriter execution");
        return ((List<? extends Member> members) -> {
            memberRepository.saveAll(members);
        });
    }
}

When you annotate a method with @Bean , you are asking the Spring container to call that method to create an instance of a the method's return type with the indicated scope.当您使用@Bean注释方法时,您要求 Spring 容器调用该方法以创建具有指示的 scope 的方法返回类型的实例。 The default scope is Application scope, which is one instance for the application, also known as singleton.默认的 scope 是 Application scope,它是应用程序的一个实例,也称为 singleton。 The annotation @StepScope has no meaning on a method that is not also annotated as @Bean .注释@StepScope对没有注释为@Bean的方法没有任何意义。 It tells the container to provide one instance of the class for the current Step -- not just one for the application.它告诉容器为当前Step提供一个 class 实例——而不仅仅是为应用程序提供一个实例。 This sets a context in which job parameters make sense, since the Step is within the context of the Job for which those parameters are defined.这设置了作业参数有意义的上下文,因为Step位于为其定义了这些参数的Job的上下文中。 The spring property referenced by the @Value annotation will be evaluated by the Spring container when it creates the bean, which it will do only if the method is annotated with @Bean (or a class annotated with @Component or an extension of that annotation).@Value注释引用的@Component属性将由 Spring 容器在创建 bean 时进行评估,只有当方法使用@Bean注释时才会执行此操作. This is why, when inactiveMemberReader(null) is called to define the reader in your Step , the job parameter "test" has a null value.这就是为什么在调用inactiveMemberReader(null)以在您的Step中定义阅读器时,作业参数“test”具有 null 值。 Without the @Bean annotation telling the Spring container to create it for the Step , it is just a plain method being passed null as the value for the test String argument.如果没有@Bean注释告诉 Spring 容器为Step创建它,它只是一个简单的方法,通过 null 作为test字符串参数的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM