[英]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
并使用以下解决方案解决它。
- Replace the
@Configuration
in the batch class I created with@Component
.将我创建的批次 class 中的
@Configuration
替换为@Component
。- Erase all
@Bean
on theJob
,Step
,Reader
,Processor
, andWriter
.擦除
Job
、Step
、Reader
、Processor
和Writer
上的所有@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.