인프런 커뮤니티 질문&답변

H N님의 프로필 이미지
H N

작성한 질문수

스프링 배치

bean 생명주기 문제 도와주세요(@Scope("step"), @Autowired)

작성

·

57

·

수정됨

0

안녕하세요. 문제가 있는데 해결 방법이 떠오르지 않아 문의드립니다.

현재 스프링 배치 4.1.4 버전을 사용하고 있고, 스프링 부트는 2.1.4 버전을 회사에서 사용하고 있습니다.

 

스프링 배치에서 JobListener를 이용해 에러가 발생할 시 잡의 마지막 부분에서 SMS 전송 시스템을 세팅해서 SMS 전송하도록 사용하려고 하는데요.

문제는 아래와 같습니다.

  1. @Scope("step") 어노테이션을 사용해야 Spel 의 값을 가져올 수 있음

  2. @Component 어노테이션을 달고, JobListener에서 @AutoWired 어노테이션을 사용하려고 할 때 @Scope("step") 영향 때문인지 해당 bean을 찾지 못함

 

즉 문제를 정리하자면, SMS class에서 Spel 의 값을 가져와야 값을 세팅할 수 있으므로, @Scope("step") 어노테이션을 달아야하는데 이 어노테이션을 붙이면 bean의 생명주기 영향으로 @AutoWired 어노테이션이 작동하지 않는 것 같습니다. 이럴 땐 어떻게 해결해야 하나요?

그리고 @Scope("step")을 아직 학습하진 않았으나 찾아보니 스프링 배치에서 사용하는 특별한 scope로 step이 실행되고 있을 때에만 해당 bean이 컨텍스트에서 유지되는 것으로 학습했습니다. 이것이 맞나요?

 

--추가

JobExecutionLisener - beforeJob 메서드 부분에 jobExecution.getExecutionContext(); 로 ExecutionContext 인스턴스를 가져온 뒤, 해당 인스턴스에 Map 형태로 값을 집어 넣습니다.

예를 들어, jobContext.put("jobId", jobId) 이런 형식으로 값을 세팅해놓고, 각 스텝에서 이 값들을 사용할 땐 @Value("#{jobExecutionContext['jobId']}" 이런 형태로 Spel를 사용합니다.

 

추가적으로 궁금한 부분은 Value 어노테이션에 어떻게 jobExecutionContext 값이 먹히는지 모르겠습니다.

원래는 이름이 똑같아야 하지 않나요? ExecutionContext 인스턴스니까 @Value("#{ExecutionContext['jobId']} 이렇게 사용을 해야할 거 같은데 왜 앞에 job이 붙어야 하는지 잘 모르겠습니다.

답변 1

0

안녕하세요, 인프런 AI 인턴입니다. H N님! 스프링 배치에서의 스코프와 빈 생명주기와 관련된 문제에 대해 설명해 드리겠습니다.

스프링 배치에서 @Scope("step") 어노테이션을 사용하실 경우, 해당 빈은 특정 스텝의 실행 시점에만 생성되고 관리되는 특수한 스코프로 전환됩니다. 따라서 스탠드얼론 빈으로서의 행동이 아니라, 스텝 내부에서만 유효한 컨텍스트를 가집니다. 이는 값 주입과 같은 부분에서 제한이 생길 수 있습니다.

해결 방법

  1. 프록시 모드 사용: @Scope("step")를 사용하면서 필요하다면 프록시 모드를 활용해서 빈 주입 문제를 피할 수 있습니다. 다음과 같이 수정해 보세요:

    @Scope(value = "step", proxyMode = ScopedProxyMode.TARGET_CLASS)
    @Component
    public class YourBean { ... }
    

    프록시 모드를 사용하면 빈이 스프링 컨텍스트에서 생성 및 참조될 때, 프록시가 대신 사용됩니다. 이는 스프링이 @Autowired를 통해 빈을 주입하는 데 필요한 참조를 허용합니다.

  2. JobExecutionListener와의 협업: JobListener와 함께 사용하는 경우라면, Job의 컨텍스트에서 데이터를 주입받을 수 있도록 스텝 스코프 내의 다른 빈이나 작업을 통해 데이터를 전달받는 방법도 가능합니다.

여기서 주의할 점은 스프링 배치의 @StepScope로 스코핑된 빈은 스텝 실행 전에 초기화되지 않는다는 것입니다. 따라서, 자원의 사용이 불필요하게 이루어지지 않도록 필요한 시점에 데이터를 이용하는 것이 주 의도입니다.

참고로, 스프링에서의 @StepScope는 컨텍스트가 스텝 실행 중일 때만 빈을 활성화하여 필요 시점에 필요한 리소스만 소모하려는 목적으로 사용됩니다.

관련 Q&A 참고: 자세한 내용은 이 링크의 질문과 답변을 참고하시면 도움이 될 수 있습니다. 여기에서도 @Scope와 관련된 다양한 논의들이 이루어진 바 있습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

H N님의 프로필 이미지
H N
질문자

--추가

JobExecutionLisener - beforeJob 메서드 부분에 jobExecution.getExecutionContext(); 로 ExecutionContext 인스턴스를 가져온 뒤, 해당 인스턴스에 Map 형태로 값을 집어 넣습니다.

예를 들어, jobContext.put("jobId", jobId) 이런 형식으로 값을 세팅해놓고, 각 스텝에서 이 값들을 사용할 땐 @Value("#{jobExecutionContext['jobId']}" 이런 형태로 Spel를 사용합니다.

 

추가적으로 궁금한 부분은 Value 어노테이션에 어떻게 jobExecutionContext 값이 먹히는지 모르겠습니다.

원래는 이름이 똑같아야 하지 않나요? ExecutionContext 인스턴스니까 @Value("#{ExecutionContext['jobId']} 이렇게 사용을 해야할 거 같은데 왜 앞에 job이 붙어야 하는지 잘 모르겠습니다.

H N님의 프로필 이미지
H N

작성한 질문수

질문하기