2025 02 17
2025-02-17¶
LocalDateTime vs Date¶
- Date
- 1970.01.01 이후의 밀리초 저장
- mutable => deprecated
- LocalDateTime
- immutable, thread-safe
- 장점
- 불변성 : 한번 생성시 값 변경 X
- 직관적인 API : 날짜, 시간, 타임스탬프, 시간대 구분하여 사용 가능. Date는 단지 타임스탬프 wrapper.
- 시간대 관리 명시성 : 시간대 포함 안하니, 시간대 필요없는 경우에 더 좋음
- Timestamp
- Unix Epoch(1970.01.01 00:00:00 UTC) 이후 경과한 시간을 나타냄. 밀리초/초단위로 표기
Date->Timestamp- 객체 내부적으로 이미 epoch 기준의 밀리초 값을 저장하고 있음
LocalDateTime->Timestamp- 타임존 정보가 없어, 타임스탬프 변환을 위해서는 어떤 타임존 기준으로 해석할 것인지 명시 필요.
Play 버전 업에 따른 Akka 변경 포인트¶
참고: https://www.playframework.com/documentation/3.0.x/Highlights28
- [AS-IS: Play 2.5.19]
- 글로벌 ActorSystem 접근
- 설정 통합 방식
- 암묵적 관리
- 전역 ActorSystem 사용
class MyActor extends Actor { def receive = { case msg => println(s"Received: $msg") } } object MyActorExample { // Play가 내부적으로 생성한 전역 ActorSystem 사용 val actorSystem = Akka.system // 액터 생성 val myActor = actorSystem.actorOf(Props[MyActor], "myActor") def sendMessage(msg: String): Unit = { myActor ! msg } }
- [TO-BE: Play 2.8.9]
- 명시적 DI 기반 ActorSystem
- 업데이트된 Akka 버전
- 설정 병합 및 구성 변화
- 라이프사이클 관리 강화
-
변경된 사용 방법
- ActorSystem 주입 예시
class MyActor extends Actor { def receive = { case msg => println(s"Received: $msg") } } @Singleton class MyActorExample @Inject()(actorSystem: ActorSystem) { // DI를 통해 주입된 ActorSystem 사용한 액터 생성 private val myActor = actorSystem.actorOf(Props[MyActor], "myActor") def sendMessage(msg: String): Unit = { myActor ! msg } }
-
Actor 바인딩을 위한 Guice Module (AkkaGuideSupport 활용)
class Module extends AbstractModule with AkkaGuiceSupport { override def configure(): Unit = { bindActor[MyActor]("myActor") // "myActor"라는 이름으로 MyActor 바인딩 } } @Singleton class MyService @Inject()(myActor: ActorRef) { def sendMessage(msg: String): Unit = { myActor ! msg } }- 단일 ActorSystem 사용
- 일반적으로 Play에는 단일
ActorSystem이 생성되어 DI 컨테이너에 바인딩. 어플리케이션 전체에서 액터 생성/관리
- 일반적으로 Play에는 단일
- 액터 생성 및 바인딩:
bindActor[MyActor]("myActor")- DI 컨테이너(Guice)에 "myActor"라는 이름으로 ActorRef 바인딩
- 내부적으로는 DI 컨테이너(Guice)에 이미 바인딩된 기본 ActorSystem을 주입받아, 그 ActorSystem 내에서
MyActor액터 인스턴스 생성- ActorSystem에서 액터 인스턴스를 생성,
ActorRef를 DI 컨테이너에 바인딩
- ActorSystem에서 액터 인스턴스를 생성,
- 생성된 액터의
ActorRef가 Guice의 바인딩에 등록되어, 나중에@Named("myActor")로 주입
- DI를 통한 주입
- 타 클래스에서
@Named("myActor")활용해ActorRef주입 시, Guice는 바인딩된 액터 참조 찾아 주입
- 타 클래스에서
asEagerSingleton()- Guice가 어플리케이션 시작 지점에 즉시 인스턴스화 하도록 하는 설정
- 일반적인 싱글톤은 처음 요청될 때 생성, eager singleton은 DI 컨테이너가 생성되는 시점에 미리 인스턴스 만들어 초기화 로직 실행.
- Guice는 기본적으로 싱글톤 바인딩을 요청 시점에 생성한다...
- (ex.
@Singleton붙여두면, 실제 주입 요청이 발생할 때 생성됨. (아하 이러면 거의다 load 시점에 주입되겠네 생성되고.))
- 바로 생성해서 스케줄링 등 지연없이 뚝딱
- 단일 ActorSystem 사용
- ActorSystem 주입 예시
- ActorSystem
- 액터를 생성, 관리, 실행하는 컨테이너
- 역할
- 액터 생성 및 관리
- 액터를 생성하는 팩토리 역할. 생성시 반드시 어떤 ActorSystem에서 생성할 것
- 생성된 액터들을 트리 구조로 관리.
- 상위 액터가 하위 액터의 오류를 감지하고 재시작하는 등 생명 주기 관리
- 메시지 디스패칭
- 액터들이 메시지 서로 주고 받을 때, 메시지 전달, 스케줄링, 디스패칭 등 담당
- 내부적으로 쓰레드풀 활용하여 액터에게 메시지 전달/처리
- 라이프사이클 관리
- ActorSystem -> 생성/종료의 책임
- 어플리케이션 종료시 모든 액터 종료, 관련 리소스 해제
- 시스템 전체의 초기화/정리 담당
- 구성 및 설정 관리
application.conf파일을 통해 Akka 관련 설정 관리, 이를 기반으로 내부 동작 방식 설정
- 액터 생성 및 관리
- Play 2.8에서는 ActorSystem이 DI 컨테이너에 싱글톤으로 등록됨에 따라, Play의 내장 라이프사이클에 의해 자동 관리 (
ApplicationLifecyle)- 별도
GuiceApplicationLoader에서 액터 바인딩/stop 필요 없이, 모듈에만 등록하면 OK
- 별도
- 업그레이드시 고려할 포인트
- DI 방식으로의 전환
- application.conf 및 Akka 설정 업데이트
- Akka API 변경사항 점검
- 라이프사이클 및 종료 처리
- 왜 DI 방식으로 변했을까...
- 전역 방식의 문제
- 암묵적 의존성 : 액터와 ActorSystem이 전역 상태로 관리, 어느 클래스가 어느 전역 객체에 의존하는지 코드상 명확 X
- 테스트 어려움 : mock 객체 (mockito)로 객체지향적으로 테스트 분리해서 진행하기 어려운건 알고...
- 유지보수 복잡성 : 변경을 했을 때 영향 범위가 어디까지인지, 어플리케이션 전반에 영향 미칠 수 있으니 조심스러워짐
- 전역 방식의 문제