Spring/series
[spring 15편] spring inject bean into enum 정리
무대포 개발자
2022. 12. 10. 13:57
728x90
반응형
source 는 Github 에 있습니다.
목차는 spring series 목차 에 있습니다.
[spring 15편] spring inject bean into enum 정리
inject bean into enum 무엇이며, 어떨 때 사용하는가?
- enum 에 bean 을 주입하는 방법에 대해 정리했습니다.
- 예를 들면, enum 에서 공통된 동작인데 구현체는 다르다면 사용하면 좋을 것 같습니다.
- 아래 예제와 같이 MemberType 별로 별도 할인 정책을 가져가야하는 부분이 있다면 사용하면 좋을 것 같습니다.
source
- 아래 예시를 설명하자면 MemberType 의 GOLD, SILVER member 의 할인율을 가져오는 예시입니다.
- enum 의 Inner class 를 만들어서 bean 을 가져와서 enum 에 동적으로 값을 변경하도록 했습니다.
- Test 는 Bean 이 미리 만들어져야하는 상황이기에 통합테스트로 (SpringBootTest) 돌렸습니다.
enum, bean, static inner class life cycle 정리
Enum
enum 은 싱글톤으로 생성되며, class 가 classLoader 에 로드될 때 생성됩니다.
jvm 이 최초 기동되면서 아래와 같이 byte code 를 만들어서 싱글톤으로 만들게 됩니다.
- 최초 기동되면서 BCI 로 코드를 만들거라 추측되는데 확실치는 않습니다. (찾아봤는데 안나오네요)
- 아래와 같이 static 으로 만들며, static 로 만들었다는 것은 jvm 로드 할 때, 전역 변수에 설정이 된 것이며, JVM 이 내려갈 때까지 GC 가 일어나지 않습니다.
Compiled from "MemberType.java"
public final class MemberType extends java.lang.Enum<MemberType> {
public static final MemberType CONST;
static {};
Code:
0: new #1 // class MemberType
3: dup
4: ldc #12 // String CONST
6: iconst_0
7: invokespecial #13 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #17 // Field CONST:LMmberType;
13: iconst_1
14: anewarray #1 // class MemberType
17: dup
18: iconst_0
19: getstatic #17 // Field CONST:LMemberType;
22: aastore
23: putstatic #19 // Field ENUM$VALUES:[LMemberType;
26: return
}
static inner class life cycle
- 클래스에 static 이 붙었다고 전역 변수처럼 동작하는 것이라 오해할 수 있습니다.
- 아래 예시를 보면 이해가 쉽습니다. 즉, 인스턴스를 생성하는 순간 메모리에 할당됩니다.
public class Test {
class InnerTest {
}
static class InnerStaticTest {
}
}
Test.InnerTest t = new Test.InnerTest();
Test.InnerTest t2 = new Test.InnerTest();
// t != t2 (다른 인스턴스이므로 다릅니다.)
Test.InnerStaticTest t = new Test.InnerStaticTest();
Test.InnerStaticTest t2 = new Test.InnerStaticTest();
// t != t2 (다른 인스턴스이므로 다릅니다.)
bean life cycle
- Jvm 이 기동되면서 ioc container 가 올라오면서 bean life cycle 이 동작하게 됩니다.
- BeanFactory 에는 classLoader 가 있으며, ClassLoader 에 Bean class 들이 등록됩니다.
Inject bean into Enum 동작 방식 정리
여기서부터는 제 생각을 쓴 것이며, 내용이 틀릴 수 있습니다. 틀린점 comment 남겨주시면 감사하겠습니다.
jvm 이 최초 기동되면서 MemberType 에 대한 static 을 만듭니다.
spring boot 이 최초 기동되면서 @SpringBootApplication 의 @ComponentScan 에 의해 MemberTypeInjector 와 GoldMemberDiscountPolicy, SilverMemberDiscountPolicy Bean 이 생성됩니다.
MemberTypeInjector 의 Bean 이 만들어지면서 PostConstruct (생성자 생성 이후 동작) 에 위해 MemberType.GOLD, MemberType.SILVER 에 MemberDiscountPolicy instance 가 설정됩니다.
MemberType Enum 에는 Bean 이 각각 inject 됐습니다.
@Getter
public enum MemberType {
GOLD("골드"),
SILVER("실버")
;
private String desc;
private MemberDiscountPolicy memberDiscountPolicy;
MemberType(String desc) {
this.desc = desc;
}
@Component
@RequiredArgsConstructor
public static class MemberTypeInjector {
private final GoldMemberDiscountPolicy goldMemberDiscountPolicy;
private final SilverMemberDiscountPolicy silverMemberDiscountPolicy;
@PostConstruct
public void postConstruct() {
MemberType.GOLD.injectMemberDiscountPolicy(goldMemberDiscountPolicy);
MemberType.SILVER.injectMemberDiscountPolicy(silverMemberDiscountPolicy);
}
}
private void injectMemberDiscountPolicy(MemberDiscountPolicy memberDiscountPolicy) {
this.memberDiscountPolicy = memberDiscountPolicy;
}
}