🚨 [에러 발생]
동영상에 대한 통계와 정산 작업, 광고에 대한 통계와 정산 작업을 배치를 통해 수행하기 위해 다음과 같이 설정하였다.
@Component
@RequiredArgsConstructor
public class BatchJobRunner {
private final JobLauncher jobLauncher;
private final Job calculateDailyVideo;
private final Job calculateDailyAdvertisement;
@Scheduled(cron = "*/10 * * * * ?") //
public void runCalculateDailyVideoJob() throws Exception {
System.out.println("Executing calculateDailyVideoJob");
JobParameters jobParameters = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis()) // 고유한 매개변수 추가
.toJobParameters();
jobLauncher.run(calculateDailyVideo, jobParameters);
}
@Scheduled(cron = "*/10 * * * * ?") //
public void runCalculateDailyAdJob() throws Exception {
System.out.println("Executing calculateDailyAdvertisementJob");
JobParameters jobParameters = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis()) // 고유한 매개변수 추가
.toJobParameters();
jobLauncher.run(calculateDailyAdvertisement, jobParameters);
}
}
@Configuration
public class JobConfig {
@Autowired
private StepConfig stepConfig;
@Bean
public Job calculateDailyVideo(JobRepository jobRepository) {
return new JobBuilder("calculateDailyVideo", jobRepository)
.start(stepConfig.calculateVideoStat())
.next(stepConfig.calculateVideoAdjustment())
.build();
}
@Bean
public Job calculateDailyAdvertisement(JobRepository jobRepository) {
System.out.println("광고 정산 및 통계");
return new JobBuilder("calculateDailyAdvertisement", jobRepository)
.start(stepConfig.calculateAdStat())
.next(stepConfig.calculateAdAdjustment())
.build();
}
}
@Configuration
@RequiredArgsConstructor
public class StepConfig {
@Autowired
private JobRepository jobRepository;
@Autowired
private PlatformTransactionManager transactionManager;
@Autowired
private VideoStatisticsTasklet videoStatisticsTasklet;
@Autowired
private VideoItemReader videoItemReader;
@Autowired
private VideoAdjustmentProcessor videoAdjustmentProcessor;
@Autowired
private VideoAdjustmentWriter videoAdjustmentWriter;
@Autowired
private AdStatisticsTasklet adStatisticsTasklet;
@Autowired
private AdItemReader adItemReader;
@Autowired
private AdAdjustmentProcessor adAdjustmentProcessor;
@Autowired
private AdAdjustmentWriter adAdjustmentWriter;
@Bean
@JobScope
public Step calculateVideoStat() {
return new StepBuilder("calculateVideoStat", jobRepository)
.tasklet(videoStatisticsTasklet, transactionManager)
.build();
}
@Bean
public Step calculateVideoAdjustment() {
return new StepBuilder("calculateVideoAdjustment", jobRepository)
.<Video, VideoAdjustment>chunk(10, transactionManager)
.reader(videoItemReader)
.processor(videoAdjustmentProcessor)
.writer(videoAdjustmentWriter)
.build();
}
@Bean
public Step calculateAdStat() {
return new StepBuilder("calculateAdStat", jobRepository)
.tasklet(adStatisticsTasklet, transactionManager)
.build();
}
@Bean
public Step calculateAdAdjustment() {
return new StepBuilder("calculateAdAdjustment", jobRepository)
.<VideoAd, AdAdjustment>chunk(10, transactionManager)
.reader(adItemReader)
.processor(adAdjustmentProcessor)
.writer(adAdjustmentWriter)
.build();
}
}
이렇게 작성을 하고 실행을 하니 다음과 같은 에러가 발생하였다.
Parameter 1 of constructor in com.example.settlement_batch.batch.config.BatchJobRunner required a single bean, but 2 were found:
💡 [해결 방법 1]
찾아보니 해당 에러는 BatchJobRunner 클래스에서 의존성을 주입할 객체를 탐색할 때, 같은 타입의 객체가 2개 이상 존재해서 발생하는 에러였다.
이때에는, 어떤 객체를 주입할 것인지 명시적으로 지정해 줘야 된다고 하는데, 이는 @Qualifier 어노테이션을 활용해서 할 수 있다.
@Component
@RequiredArgsConstructor
public class BatchJobRunner {
private final JobLauncher jobLauncher;
@Qualifier("calculateDailyVideo")
private final Job calculateDailyVideo;
@Qualifier("calculateDailyAdvertisement")
private final Job calculateDailyAdvertisement;
@Scheduled(cron = "*/10 * * * * ?") //
public void runCalculateDailyVideoJob() throws Exception {
System.out.println("Executing calculateDailyVideoJob");
JobParameters jobParameters = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis()) // 고유한 매개변수 추가
.toJobParameters();
jobLauncher.run(calculateDailyVideo, jobParameters);
}
@Scheduled(cron = "*/10 * * * * ?") //
public void runCalculateDailyAdJob() throws Exception {
System.out.println("Executing calculateDailyAdvertisementJob");
JobParameters jobParameters = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis()) // 고유한 매개변수 추가
.toJobParameters();
jobLauncher.run(calculateDailyAdvertisement, jobParameters);
}
}
그렇지만, 이렇게 해도 여전히 동일한 에러가 발생하고 있었다. 🥹
💡 [해결 방법 2]
@Qualifier 어노테이션에 위와 같은 문구가 뜨는 것을 알 수 있었다. Lombok이 Qualifier를 생성자로 복사하지 못한다는 것이었다.
@RequiredArgsConstructor는 Lombok에서 제공하는 것인데, 의존성 주입 시 필요한 생성자를 자동으로 만들어주는 역할을 한다. 하지만, @RequiredArgsConstructor는 기본적으로 필드에 대해서만 파라미터로 포함을 시켜 생성자를 만들어주는 것이었다.
때문에, @Qualifier에 대해서는 @RequiredArgsConstructor가 복사하지 못해 같은 타입의 객체를 주입해야 하는 상황에서 어떠한 것을 주입해야 할지 알 수 없어 에러가 발생한 것이었다.
이를 해결하기 위해서는 직접 생성자를 만들어 주어 생성자 주입 방식으로 해결을 해야 했다.
@Component
public class BatchJobRunner {
private final JobLauncher jobLauncher;
private final Job calculateDailyVideo;
private final Job calculateDailyAdvertisement;
public BatchJobRunner(JobLauncher jobLauncher, @Qualifier("calculateDailyVideo") Job calculateDailyVideo, @Qualifier("calculateDailyAdvertisement") Job calculateDailyAdvertisement) {
this.jobLauncher = jobLauncher;
this.calculateDailyVideo = calculateDailyVideo;
this.calculateDailyAdvertisement = calculateDailyAdvertisement;
}
@Scheduled(cron = "*/10 * * * * ?") //
public void runCalculateDailyVideoJob() throws Exception {
System.out.println("Executing calculateDailyVideoJob");
JobParameters jobParameters = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis()) // 고유한 매개변수 추가
.toJobParameters();
jobLauncher.run(calculateDailyVideo, jobParameters);
}
@Scheduled(cron = "*/10 * * * * ?") //
public void runCalculateDailyAdJob() throws Exception {
System.out.println("Executing calculateDailyAdvertisementJob");
JobParameters jobParameters = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis()) // 고유한 매개변수 추가
.toJobParameters();
jobLauncher.run(calculateDailyAdvertisement, jobParameters);
}
}
이렇게 하니 에러 없이 정상적으로 배치 작업을 수행할 수 있었다. 😚😚
🧑💻
[회고]
Intellij에서는 컴파일 오류나 문법 오류 등 여러 오류에 대해서 코드 아래에 빨간 줄로 표현해 준다. 덕분에, 해당 카테고리류 에러에 대한 것을 쉽게 잡을 수 있다.
노란 줄로도 표현을 하는데, 이것은 보통 경고 정도이다. 실행은 되지만 개선 사항이 필요할 때 주로 노란 줄로 표현을 해주는 것이다.
여태 노란 줄에 대한 코드를 수정하지 않아도 실행에는 문제가 없었다. 하지만, 이번을 계기로 노란 줄로 표현된 코드들에 대해서 한 번씩 살펴보아야겠다는 생각을 하게 됐다.
'Trouble Shooting > Spring Boot' 카테고리의 다른 글
로컬 DB 인스턴스 우선 참조 (0) | 2024.07.22 |
---|---|
Slave DB가 Master DB를 제대로 복제하지 못하는 문제 (0) | 2024.07.18 |
'@NotNull' & 'nullable=false' - 우린 같아요! 아니 달라요! 아니.. 같..! (0) | 2024.06.02 |
[Spring boot] - No suitable driver found (0) | 2024.05.24 |
com.amazonaws.SdkClientException: Failed to connect to service endpoint 에러 (0) | 2022.07.21 |