Spring state machine
출처 모름: 그냥 알던거 정리
🚫 아래 내용은 주관적인 생각이므로 사실과 다를 수 있습니다.
개요
일반적인 State machine의 개념을 Spring Project로 그대로 가져온 Framework입니다.
구성
-
State: 관리의 대상이 되는 상태 값
- Initial State: 초기 상태값
- End State: 완료 상태값
- Source State: 변경 이전의 원래 상태
- Target State: 변경을 목표로 하는 상태
- Initial State: 초기 상태값
- StateMachine: State의 변경 규칙 명세
-
Event: State에 변경이 발생하게 되는 계기
ex) 장착, 탈착, 폐기 등 - Transition: State의 변경, 변이, 변화 등
-
Guard: Event가 발생했을 때, 조건을 검증하는 관문(반환값이 false일 경우, Transition은 일어나지 않는다.)
- 폐기 Event 발생시의 Guard 예시) Source State == 유휴 && 폐기 승인 목록에 존재
-
Action: Transition 발생 후 실행되는 행위
- 폐기 Event 발생시의 Action 예시) 폐기 완료 알림 전송
의존성
Gradle
implementation 'org.springframework.statemachine:spring-statemachine-core:2.1.3.RELEASE'
2022년 12월 26일 기준 최신 버전은 3.2.0이나,
해당 버전에는 기존의 상태 처리 방식들이 Deprecated 처리 되어 있고
비동기 처리를 강제하고 있어개발 편의상 2.1.3.RELEASE 버전을 사용했습니다.
사용 방법 - 2.1.3.RELEASE 문서 Link
-
State 및 Event 정의
관리할 State와 Event를 Enum 타입으로 정의합니다.
String 타입으로도 가능하지만, 유지보수 편의성을 위해 Enum 타입으로 정의하겠습니다.
-
State machine 설정
- Entity에 필드로 State 추가
- Entity Repository 생성
- StateMachineConfigurerAdapter를 상속받는 설정 Class를 생성합니다.
StateMachineFactory를 사용할 수 있도록 @EnableStateMachineFactory을 꼭 추가해줍니다.-
State 등록
위와 같이 Initial State와 End State, 그리고 사용할 모든 State를 등록해줍니다. -
Transition 설정
위와 같이 어떤 Source state에서 어떤 Event가 발생했을 때 어떤 Target state로 Transition이 발생하고,해당 Transition에 어떤 guard나 action이 있는지 추가해줍니다. -
StateMachineListener 등록(선택)
필요하다면, State의 변경사항을 감지해 특정 로직을 수행하는 Listener를 등록합니다.
-
- Entity에 필드로 State 추가
-
MediaStateChangeInterceptor
위 인터셉터의 목적은 state 변경사항을 Entity에 반영하기 위함입니다.
그러므로 Entity를 수정하기 위해 Entity Repository를 필드로 가집니다.
StateMachineInterceptorAdapter<>를 상속받아,
State가 변경되기 전에 호출되는 preStateChange 메소드를 Override합니다.
preStateChange 메소드 안에서 메시지의 Header를 통해 Entity의 id를 찾아서
변경된 state로 Entity를 수정해줍니다. -
Entity Service에 StateMachineFactory 추가
-
MEDIA_ID_HEADER: 아래에서 다루는 Message의 HeaderName이 될 값
-
MediaStateChangeInterceptor: state 변경사항을 Entity에 반영하는 인터셉터
Entity Service에 위 두 필드와 함께 StateMachineFactory를 추가합니다.
-
StateMachine 인스턴스 가져오기
build(Long mediaId) 메소드에서는 stateMachineFactory의
getStateMachine(String machineId) 메소드를 통해
StateMachine 인스턴스를 생성해 반환 받습니다.
Accessor를 이용해 state 변경사항을 반영하는 인터셉터를 추가하고,
마지막으로 Media(Entity)의 state로 StateMachine을 초기화 해 반환합니다. -
Event 생성
sendEvent(Long mediaId, StateMachine<> sm, MediaEvent event) 메소드에서는
StateMachine에 Event를 전송합니다.
이 때 MEDIA_ID_HEADER를 headerName으로 가지는 Header를 Message에 추가해서
Event가 발생한 Media(Entity)의 id를 전달합니다. -
실 사용 예시
위 4.1에서 설명한 build 메소드로 StateMachine 인스턴스를 받아,
위 4.2에서 설명한 sendEvent 메소드를 통해 Event를 전송합니다.
-
-
-
실 사용 흐름 정리
-
Entity의 State로 초기화 된 StateMachine에 Event를 전송합니다.
-
Guard 검증 - True인 경우만 통과
-
Action 실행
-
StateMachineListenerAdapter의 transition Method 실행
-
인터셉터에서 State의 변경을 수신해 해당 Entity의 State를 변경
-
StateMachineListenerAdapter의 stateChanged Method 실행
-
-
기타
- Guard
위의 Guard 예시는 Event가 발생했을 때 Header로 전달한 Media(Entity)의
id를 StateContext에서 가져와 MediaRepository(Entity Repository)를 활용해
해당 Media(Entity)를 찾아냅니다.
그리고 찾아낸 Media(Entity)가 Transition 발생 조건에 부합하는지
확인(boolean값 반환)합니다.- 발생 조건을 검증하는데에 Entity가 필요없다면,
MediaRepository를 설정 class에 추가할 필요가 없습니다.
- 발생 조건을 검증하는데에 Entity가 필요없다면,
- Action
Action 또한 Guard와 마찬가지로 StateContext를 받아
Transition이 끝나고 실행할 행동들을 정의합니다.
- Guard
댓글남기기