Reputation: 15
I implemented now with spring batch
to manage dormant account. The following problems occurred while using the spring batch
.
Spring Batch When I run using joblauncher, I think the job is not running
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
.
I wanted to run Job
somehow using the @Scheduled
and solved it with the following solution.
- Replace the
@Configuration
in the batch class I created with@Component
.- Erase all
@Bean
on theJob
,Step
,Reader
,Processor
, andWriter
.
After doing so, Job
worked as I wanted and got a log.
I solved the problem, but there was another problem.
In a lot of example, even spring official documents attached @Bean
at all of Job.
Furthermore, it seemed that JobParameter
could not be used without @Bean
attached. (When I tried to use the JobParameter
, the initial value was null
.)
I'm going to ask you a real question now.
Spring Batch
will also be used in the field. And it's expected to put @Bean
, as it says in the official document. 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);
});
}
}
Upvotes: 0
Views: 517
Reputation: 76
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. The default scope is Application scope, which is one instance for the application, also known as singleton. The annotation @StepScope
has no meaning on a method that is not also annotated as @Bean
. It tells the container to provide one instance of the class for the current Step
-- not just one for the application. 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. 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). This is why, when inactiveMemberReader(null)
is called to define the reader in your Step
, the job parameter "test" has a null value. 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.
Upvotes: 1