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) 돌렸습니다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// MemberType.java | |
@Getter | |
public enum MemberType { | |
GOLD("골드"), | |
SILVER("실버") | |
; | |
private String desc; | |
private MemberDiscountPolicy memberDiscountPolicy; | |
MemberType(String desc) { | |
this.desc = desc; | |
} | |
@Component | |
@RequiredArgsConstructor | |
private 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; | |
} | |
} | |
// MemberDiscountPolicy.java | |
public interface MemberDiscountPolicy { | |
String getDiscountRate(); | |
} | |
// GoldMemberDiscountPolicy.java | |
@Component | |
@RequiredArgsConstructor | |
public class GoldMemberDiscountPolicy implements MemberDiscountPolicy { | |
@Override | |
public String getDiscountRate() { | |
return "30%"; | |
} | |
} | |
// SilverMemberDiscountPolicy.java | |
@Component | |
@RequiredArgsConstructor | |
public class SilverMemberDiscountPolicy implements MemberDiscountPolicy { | |
@Override | |
public String getDiscountRate() { | |
return "10%"; | |
} | |
} | |
// MemberTypeTest.java | |
@ExtendWith(SpringExtension.class) | |
@SpringBootTest | |
public class MemberTypeTest { | |
@Test | |
@DisplayName("Enum Bean 주입 테스트") | |
public void injectBeanIntoEnumTest() throws Exception { | |
MemberType memberType = MemberType.GOLD; | |
String discountRate = memberType.getMemberDiscountPolicy().getDiscountRate(); | |
Assertions.assertEquals("30%", discountRate); | |
memberType = MemberType.SILVER; | |
discountRate = memberType.getMemberDiscountPolicy().getDiscountRate(); | |
Assertions.assertEquals("10%", discountRate); | |
} | |
} | |
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;
}
}
Reference
'Spring > series' 카테고리의 다른 글
[spring 17편] spring-boot, docker, flyway 활용해서 로컬 mysql 테스트 환경 구축 (0) | 2022.12.19 |
---|---|
[spring 16편] Rest Template, WebClient 정리 (0) | 2022.12.15 |
[spring 14편] spring api service, domain layer unit test 정리 (0) | 2022.11.26 |
[spring 13편] spring api integration test 정리 (0) | 2022.11.26 |
[spring 12편] spring boot 통합 test 실행 중 mybatis mapper not found 문제 정리 (0) | 2022.08.29 |
댓글