-
Spring batch jobScope, stepScopeDEV 2023. 12. 2. 21:21
Spring batch의 jobScope, stepScope를 알아가기 위한 흐름
jobScope, stepScope → bean scope → application context → IoC, DI
IoC부터 시작해 보자.
IoC (Inversion of Control)
- 제어의 역전
- 객체 생명주기, 메서드 호출 외부에서 관리 - 일반적인 의존성에 대한 제어 → 객체 내에서 제어
public class Mundo { private FrostfireGauntlet frostfireGauntlet; private BerserkerShoes berserkerShoes; private DoranShield doranShield; public Mundo(){ this.frostfireGauntlet = new FrostfireGauntlet(); this.berserkerShoes = new BerserkerShoes(); this.doranShield = new DoranShield(); } }
- 의존성을 외부의 누군가(spring, IoC container) 제어 → 객체 내 의존성 제어권이 없다.
public class Mundo { private Gauntlet gauntlet; private Shoes shoes; private Shield shield; public Mundo(Gauntlet gauntlet, Shoes shoes, Shield shield){ this.gauntlet = gauntlet; this.shoes = shoes; this.shield = shield; } } pubilic interface Gauntlet{ } pubilc class FrostfireGauntlet implements Gauntlet{ }
- 제어권이 내부에서 외부로 역전 → 내가 작성한 코드를 외부의 누군가 실행
→ 목적 = 역할과 관심을 분리
→ 필요한 객체를 외부에서 생성하여 필요한 객체에 주입해 주겠다.
→ 할리우드 원칙 (Don’t call us, We’ll call you)
→ 내가 알아서 필요한 객체 생성해서 주입해 줄 테니, 넌 가만히 있어..
→ IoC principle
Difference between DIP and IoC
그렇다면 DIP와 IoC의 차이는 무엇일까?
DIP (Dependency Inversion Principle)
- 의존 역전 원칙
- 상위 레벨 모듈이 하위 레벨 모듈의 구현에 의존하지 않고
→ 저수준 모듈이 고수준 모듈의 인터페이스에 의존
→ 의존 방향이 역전
public class Mundo { private FrostfireGauntlet frostfireGauntlet; private BerserkerShoes berserkerShoes; private DoranShield doranShield; public Mundo(){ this.frostfireGauntlet = new FrostfireGauntlet(); this.berserkerShoes = new BerserkerShoes(); this.doranShield = new DoranShield(); } } public class Mundo { private Gauntlet gauntlet; private Shoes shoes; private Shield shield; public Mundo(Gauntlet gauntlet, Shoes shoes, Shield shield){ this.gauntlet = gauntlet; this.shoes = shoes; this.shield = shield; } } pubilic interface Gauntlet{ } pubilc class FrostfireGauntlet implements Gauntlet{ }
- 근데 이건 위에서 봤던 IoC에 대한 예제 아니었나? 왜 DIP가 적용되어있는 거지?
IoC와 DIP가 뭔가 헷갈리는데?
한 단계씩 가보면
1. init
public class Mundo { private FrostfireGauntlet frostfireGauntlet; private BerserkerShoes berserkerShoes; private DoranShield doranShield; public Mundo(){ this.frostfireGauntlet = new FrostfireGauntlet(); this.berserkerShoes = new BerserkerShoes(); this.doranShield = new DoranShield(); } }
2. IoC 적용 → 의존 외부 주입 → 제어권이 내부에서 외부로
public class Mundo { private FrostfireGauntlet frostfireGauntlet; private BerserkerShoes berserkerShoes; private DoranShield doranShield; public Mundo(FrostfireGauntlet frostfireGauntlet, BerserkerShoes berserkerShoes, DoranShield doranShield){ this.frostfireGauntlet = frostfireGauntlet; this.berserkerShoes = berserkerShoes; this.doranShield = doranShield; } }
3. DIP 적용 → 고수준 모듈이 저수준 모듈에 의존하지 않도록, 고수준 입장에서 만든 인터페이스에 저수준 모듈이 의존 → 의존 방향 역전
public class Mundo { private Gauntlet gauntlet; private Shoes shoes; private Shield shield; public Mundo(Gauntlet gauntlet, Shoes shoes, Shield shield){ this.gauntlet = gauntlet; this.shoes = shoes; this.shield = shield; } } pubilic interface Gauntlet{ } pubilc class FrostfireGauntlet implements Gauntlet{ }
- 우리는 알게 모르게 IoC와 DIP를 함께 사용하고 있고, 스프링 또한 함께 사용하길 강력히 권장하고 있기도 하다.
IoC, DIP의 공통된 목적
- 클래스 간 결합을 느슨히 하기 위함
→ 하나의 클래스에서 변경 발생 시 다른 클래스의 미치는 영향을 최소화
→ application을 지속가능하고 확장성 있게 만들 수 있다.
Relationship between IoC and DI
spring에서는 IoC와 DI는 항상 같이 이야기되던데...
DI (Dependency Injection)
In software engineering, dependency injection is a design pattern in which an object or function receives other objects or functions that it depends on. A form of inversion of control, dependency injection aims to separate the concerns of constructing objects and using them, leading to loosely coupled programs.
- wikipedia- 위키피디아에 따르면 dependency injection(DI)는 디자인 패턴이고, inversion of control(IoC)의 한 종류
- 관심의 분리, 느슨한 연결을 목표로 한다.
Principle, Pattern
- principle → IoC (Inversion of Control)
- pattern → Factory, Template Method, Strategy, Dependency Injection(DI)
- Ioc는 제어의 역전이라는 원칙, 아이디어이고, DI는 이를 해결하는 패턴 중 하나
- 위 코드를 예로 들면 IoC는 ‘Mundo class가 자신의 아이템을 스스로 선택할 수 없게 한다,
제어권을 외부로 넘긴다.’라는 추상적인 개념. 누가 어떻게 아이템을 주입해 줄지는 중요하지 않다.
- DI는 Mundo class에 아이템을 위부에서 주입해주는 구체적인 행위
DI in Spring
- 그럼 스프링에서의 DI를 간단히 살펴보면..
- 스프링 프레임워크에서 IoC를 위해 객체(bean)를 등록, 생성, 조회, 반환, 관리를 위한 컨테이너
→ IoC 컨테이너 (spring container)
- 가져온 그림에서 약간 잘못된 부분이 있는데 A객체가 IoC컨테이너에 생성된 객체(bean)를 주입받기 위해서는 A객체도 bean으로 등록되어있어야 한다.
→ A객체도 IoC 컨테이너 안에 있어야 한다
Bean
- 스프링에서 제어권을 가지고 직접 만들어 관계를 부여하는 객체
- intellij에서 코드라인 옆에 콩으로 표시
- intellij Spring Beans Dependencies diagram
Bean factory
- 스프링 IoC를 담당하는 핵심 컨테이너, interface
- bean 등록, 생성, 조회, 반환 관리
- bean factory를 바로 사용하지 않고 이를 확장한 application context를 사용
application context
- bean factory를 확장한 IoC 컨테이너
- 스프링의 각종 부가 기능지원
- spring bean으로 등록되면 spring이 자동으로 생성, 주입해 주기 때문에 직접 사용할 일은 별로 없다.
- 필드 주입, setter 주입, 생성자 주입
Bean scope
- 객체(bean)가 영향을 미치는 범위 ⇒ scope
- application context(IoC container)가 context가 시작하기 전에 모든 빈을 생성
- singleton(default), prototype, request…
- singleton 객체를 하나만 생성 → 각 thread가 공유 → non-thread safe → bean은 상태를 가져서는 안 됨
- prototype으로 호출 시마다 객체 생성도 가능하지만 리소스 이슈
@Component @Scope("singletone") public class Mundo { @PostConstruct public void load() { loadItems(); } @PreDestroy public void release() { releaseItems(); } }
Bean scope in Spring batch
- batch job 시작 → jobInstance 생성 → jobInstance = jobName + jobParameter
- 동일한 jobParmeter로 동일한 job을 두 번 이상 실행 할 수 x - 기본적인 spring bean의 생성 시점 → application의 시작 → default = singleton scope
- jobScpe, stepScope → job, step의 실행 시점에 Spring bean으로 생성
- request scope: request 받을 때 bean을 생성하고 request가 반환되면 bean을 반환하는 것처럼
- job, step의 시작, 종료 → bean을 생성, 반환 ⇒ jobScope, stepScope - jobScope, stepScope을 통해 bean 생성을 지연시켜서 얻는 이점
- 아래 예제에서 jobScope가 없다면 application이 실행되는 시점에만 jobPrameter를 주입 가능
(정확히는 jobParameter를 사용하려면 jobScope, stepScore를 무조건 사용해야 하지만.. 아무튼 개념설명을 위해)
→ jobScpe를 통해 controller, service 같은 비즈니스 로직 레벨에서 jobParmeter를 할당 가능
→ application 실행 후에도 동적으로 reader, processer, writer를 동적으로 만들 수 있다.
- 병렬처리에 안전 → singleton scope로 생성한다면 → non-thread safe → job, step의 시작, 종료 → bean을 각각 생성, 반환
@Bean @JobScope public Step analysisWinRateStep(@Value("#{jobParameters[requestDate]}") final String requestDate) { log.info("requestDate: {}", requestDate); return stepBuilderFactory.get("analysisWinRateStep") .<LolWinRate, AnalysisWinRate>chunk(100) .reader(lolWinRateReader()) .processor(analysisWinRateProcessor()) .writer(winRateWriter()) .build(); }
Fin.
- principle → IoC (Inversion of Control), DIP (Dependency Inversion Principle)
- IoC, DIP는 원칙 - pattern → DI (Dependency Injection)
- DI는 IoC를 따르기 위한 디자인 패턴 - framework → Spring DI / IoC
- DI를 자동으로 해주면서 프로그램의 제어권을 가짐
Reference
728x90'DEV' 카테고리의 다른 글
LangChain에 대하여 (1) 2023.12.03 JIT compiler & GraalVM in java (2) 2023.12.03 Elasticsearch에서의 relation (1) 2023.12.02 Spring batch integration test (feat.Elasticsearch) (0) 2023.12.02 K8S, DNS 간헐적 5~15초 지연 (0) 2023.12.02 - 제어의 역전