#9 ์์กด๊ด๊ณ ์๋์ฃผ์ ์์ ์๊ธฐ๋ ๋ฌธ์ (+Lombok ์๊ฐ)
by JiwonDevํด๋น ๊ธ์ ๊น์ํ๋์ ์ธํ๋ฐ ๊ฐ์๋ฅผ ๊ณต๋ถํ๊ณ ์ ๋ฆฌํ ๋ด์ฉ์ ๋๋ค.
๋ง์ ๊ฐ๋ฐ์ ํด๋ณด๋ฉด ์๊ฒ ์ง๋ง, ์ต๊ทผ์ ์ฌ์ฉํ๋ ๋ฐฉ์์ Side-effect๋ฅผ ์์ ๊ธฐ ์ํด ๊ฐ๋ฅํ ๊ฐ์ฒด๋ค์ ๋ถ๋ณ(final)์ผ๋ก ๋ง๋ค๊ฒ ๋๋ค. ๊ทธ๋ฐ๋ฐ ๋งค๋ฒ ์์ฑ์๋ฅผ ๋ง๋ค๊ณ , ์ฃผ์ ๋ฐ์ ๊ฐ์ ๋์ ํ๋ ์ฝ๋๋ฅผ ๋ง๋ค๊ณ .. ์ด๋ฅผ ์๋ํํด์ฃผ๋ ๋๊ตฌ๋ ์์๊น?
#Lombok ์๊ฐ (๋์ค์ ๋ฐ๋ก ๋ค๋ฃฐ ์์ )
๊ทธ๊ฒ ๋ฐ๋ก Lombok ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค. ์ด๋ ธํ ์ด์ ๊ธฐ๋ฐ์ผ๋ก Getter, Setter๋ฑ์ ์๋์์ฑ ํด์ค๋ค๊ณ ๋ค์ด๋ณธ ์ ์์ ๊ฒ์ด๋ค. ์ง๊ธ์ ํ๋ํ๋ ์ฝ๋๋ฅผ ์์ฑํ์ง๋ง ์ค์ ํ๋ก์ ํธ์์๋ Lombok์ ๋๋ถ๋ถ ์ฌ์ฉํ๊ธฐ์, ์กฐ๊ธ ์๋น๊ฒจ์ ๋ฏธ๋ฆฌ ์๊ฐ๋ฅผ ํ๋ ค๊ณ ํ๋ค.
// ๊ธฐ์กด ์ฝ๋ @Component public class OrderServiceImpl implements OrderService { private final MemberRepository memberRepository; private final DiscountPolicy discountPolicy; // @Autowired ์์ฑ์๊ฐ ๋จ ํ๋์ธ ๊ฒฝ์ฐ, ์๋ตํด๋ ๋๊ฐ์ด ๋์ํ๋ค. public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) { this.memberRepository = memberRepository; this.discountPolicy = discountPolicy; } }
์์ ์ฝ๋๋ฅผ Lombok ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ ๊ฐ๋จํ๊ฒ ๋ง๋ค์ด๋ณด์. ์ฌ๊ธฐ์์๋ @RequiredArgsConstructor๋ฅผ ์ด์ฉํ์ฌ final์ด ๋ถ์ ํ๋๋ง ๋ชจ์์ ์์ฑ์๋ฅผ ์๋์ผ๋ก ๋ง๋ค์ด ๋ณด๊ฒ ๋ค.
@Component @RequiredArgsConstructor public class OrderServiceImpl implements OrderService { private final MemberRepository memberRepository; private final DiscountPolicy discountPolicy; }
์ฐธ๊ณ ๋ก IntelliJ์์ Annotation Processing ๊ธฐ๋ฅ์ ํ์ฑํ ์ํค๋ฉด Lombok์ด ์ ์ฉ๋ ์ฝ๋๋ฅผ ์๋์์ฑ์ผ๋ก ์ฌ์ฉํ ์ ์๋ค.

์คํ๋ง๋ถํธ์์ Lombok์ ์ ์ฉํ๋ ค๋ฉด build.gradle์ ๋ค์๊ณผ ๊ฐ์ด ์ถ๊ฐํด์ฃผ๋ฉด ๋๋ค.
plugins { id 'org.springframework.boot' version '2.3.2.RELEASE' id 'io.spring.dependency-management' version '1.0.9.RELEASE' id 'java' } group = 'hello' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' //** lombok ์ค์ ์ถ๊ฐ ์์ configurations { compileOnly { extendsFrom annotationProcessor } } //lombok ์ค์ ์ถ๊ฐ ๋ ** repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter' //** lombok ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ถ๊ฐ ์์ compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testCompileOnly 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' //lombok ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ถ๊ฐ ๋ ** testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' } } test { useJUnitPlatform() }
# ๋ค์ ๋ณธ๋ก , ์กฐํ ๋น์ด 2๊ฐ ์ด์(์์ ๊ด๊ณ)์ผ ๋
@Autowired๋ฅผ ์ด์ฉํด์ ์์กด๊ด๊ณ๋ฅผ ์๋๋ฑ๋ก ํ ๋, ํด๋นํ๋ ๋น์ด ์๊ฑฐ๋ ๋น ์ปดํฌ๋ํธ์ ์ด๋ฆ์ด ์ค๋ณต๋๋ ๊ฒฝ์ฐ๋ ์ด๋ป๊ฒ ์ฒ๋ฆฌ๋๋์ง ์์๋ณด์๋ค. ํ์ง๋ง ์ค๋ณต์ด ์๋๋ผ ์์๊ด๊ณ์ธ ๊ฒฝ์ฐ์๋ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ๊น?
- Autowried๋ ๋น์ ํ์ (Type)์ ์กฐํํ์ฌ ์์กด๊ด๊ณ๋ฅผ ๋ฑ๋กํ๋ค.
- ์ฆ ac.getBean(DiscountPolicy.class)๋ฅผ ์ด์ฉํด์ ํด๋น ๋น์ ๊ตฌํ์ฒด๋ก ๋ฑ๋กํ๋ ๊ฒ์ฒ๋ผ ๋์ํ๋ค.
- ๊ทธ๋ ๋ค๋ฉด DiscountPolicy์ ํ์ํ์ ์ธ FixDiscount ์ RateDiscount๋ ์ด๋ป๊ฒ ๊ตฌ๋ถํ ๊น?
@Autowired private DiscountPolicy discountPolicy
// ๋ ์ค ๋ฌด์์ ์์กด๊ด๊ณ๋ก ๋ฑ๋กํด์ผํ๋์ง ์คํ๋ง ํ๋ ์์ํฌ๊ฐ ์ ์ ์์๊น? @Component public class FixDiscountPolicy implements DiscountPolicy {} @Component public class RateDiscountPolicy implements DiscountPolicy {}
์ ๋ต์ '์๋์ผ๋ก ๋ฑ๋กํ์ง ๋ชปํ๋ค'์ด๋ค. NoUniqueBeanDefinitionException์ด ๋ฐ์ํ๊ฒ ๋๋๋ฐ, ์ค๋ฅ ๋ด์ฉ์ ์ฝ์ด๋ณด๋ฉด ๊ฐ์ ํ์ ์ธ ๋น์ด 2๊ฐ๊ฐ ์์ด ๋งค์นญ์ด ๋ถ๊ฐ๋ฅํ๋ค๊ณ ์น์ ํ๊ฒ ์๋ ค์ค๋ค.
NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.core.discount.DiscountPolicy' available: expected single matching bean but found 2: fixDiscountPolicy,rateDiscountPolicy
๋ฌผ๋ก DiscountPolicy ์ธํฐํ์ด์ค ๋์ ์ ํ์ํ์ ์ ๊ตฌํ์ฒด๋ฅผ ์ง์ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ๋ ์์ผ๋, ์ด๋ DIP๋ฅผ ์๋ฐฐํ๊ณ ์์์ ๋ฐฐ์ ๋ ๋คํ์ฑ์ ์งํค์ง ๋ชปํ๋ ์ฝ๋๊ฐ ๋๋ฒ๋ฆฐ๋ค. ๋๋ ์คํ๋ง ๋น์ ์๋(@Bean)์ผ๋ก ์ง์ ์ง์ ํ์ฌ ํด๊ฒฐํ ์ ์๊ฒ ์ง๋ง, ์์กด ๊ด๊ณ ์๋ ์ฃผ์ ์์๋ ํด๊ฒฐํ๋ ์ฌ๋ฌ ๋ฐฉ๋ฒ๋ค์ด ์๋ค.
# ํด๊ฒฐ์ฑ
@Autowired [filed-name]
[ @Autowired ] ๋ ํ์ ๋งค์นญ์ ์๋ํ ๋ ๋์ผํ ์ฌ๋ฌ ๋น์ด ์์ผ๋ฉด ํ๋ ์ด๋ฆ, ํ๋ผ๋ฏธํฐ ์ด๋ฆ์ผ๋ก ๋น ์ด๋ฆ์ ๋งค์นญํ๋ค. ์ฆ ๋จ์ํ ๋ณ์ ์ด๋ฆ์ ๋ฑ๋กํ๊ณ ์ํ๋ ๋น์ด๋ฆ์ผ๋ก ๋ณ๊ฒฝํ๊ธฐ๋ง ํด๋ ํด๋น ์ด๋ฆ์ ๋น์ ์ฐพ์์ ๋ฑ๋กํด์ค๋ค.
* ์์์ ์ปดํฌ๋ํธ ์๋์ค์บ์ผ๋ก ๋ฑ๋กํ ๋น ์ด๋ฆ์ด ํด๋์ค๋ช ๊ณผ ๋์ผํ ์ด์ . (MyClass -> myClass ๋ก ์์ฑ)
// ์๋ฌ. ํด๋น ํ์
์ ๋น์ด ์ฌ๋ฌ๊ฐ์ @Autowired private DiscountPolicy discountPolicy // ํด๋น ํ์
์ ๋น์ด ์ฌ๋ฌ๊ฐ์ง๋ง, rateDiscountPolicy ๋ผ๋ ์ด๋ฆ์ ๊ฐ์ง ๋น์ด ์์ผ๋ฏ๋ก ์๋๋ฑ๋ก. @Autowired private DiscountPolicy rateDiscountPolicy
๋จ, ํ์ ๋งค์นญ์ด ์คํจํ์ ๋๋ง(=๋น์ด ์ฌ๋ฌ๊ฐ์ผ ๋) ํ๋, ํ๋ผ๋ฉํ ์ด๋ฆ์ ์ถ๊ฐ์ ์ผ๋ก ์ฌ์ฉํ๋ค๋ ๊ฒ์ ์์ง๋ง์.
@Qualifier ๋ผ๋ฆฌ ๋งค์นญํ๊ธฐ
[ @Qualifier ] ๋ ์ถ๊ฐ์ ์ธ ๊ตฌ๋ถ์๋ฅผ ๋ถ์ฌ์ฃผ๋ ๋ฐฉ๋ฒ์ด๋ค. ๋ง์น ๋น ์ด๋ฆ์ ๋ฑ๋กํด์ฃผ๋ ๊ฒ์ฒ๋ผ ์ฌ์ฉํ์ง๋ง, ์๋ ๋ฑ๋ก์ ํ๊ธฐ์ํด ๊ตฌ๋ถ์๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ผ ๋ฟ ์ค์ ๋น ์ด๋ฆ์ด ๋ณ๊ฒฝ๋๋ ๊ฒ์ ์๋๋ค.
๋ง์ฝ ํด๋น ์ด๋ฆ์ Qualifier๊ฐ ์๋ ๊ฒฝ์ฐ, ๊ฐ์ ์ด๋ฆ์ ์คํ๋ง ๋น์ ์ฐพ์์ ์ฐ๊ฒฐํด์ฃผ๊ธด ํ์ง๋ง ๋ณดํต์ ๊ทธ๋ ๊ฒ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ์๋ค. Qualifier์ ์ด๋ฆ์ ์ง์ ํด์ฃผ์.
@Component @Qualifier("mainDiscountPolicy") public class RateDiscountPolicy implements DiscountPolicy {} @Component @Qualifier("fixDiscountPolicy") public class FixDiscountPolicy implements DiscountPolicy {} // ์ปดํฌ๋ํธ ์ค์บ์ด ์๋๋ผ ์๋์ผ๋ก ๋ฑ๋กํ๋ ๊ฒฝ์ฐ @Bean @Qualifier("mainDiscountPolicy") public DiscountPolicy discountPolicy() { return new ... }
@Autowired // ํ๋ผ๋ฉํ ์์ @Qualifier๋ฅผ ์ถ๊ฐ๋ก ์ ์ด์ค๋ค. public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy){ this.memberRepository=memberRepository; this.discountPolicy=discountPolicy; }
@Primary ์ฌ์ฉํ๊ธฐ
์ด๋ ์ด๋ฆ์ ์ง์ ํด์ฃผ๋ ๊ฒ ์๋๋ผ, ์ฐ์ ์์๋ฅผ ์ ํ๋ ๋ฐฉ๋ฒ์ด๋ค. @Autowired์์ ์ฌ๋ฌ ๋น์ด ๋งค์นญ๋๋ฉด, @Primary ๋น์ด ์ฐ์ ๊ถ์ ๊ฐ์ง๊ฒ ๋๋ค. ์์ @Qualifier์ ๊ฒฝ์ฐ ๋ชจ๋ ์ฝ๋์ ์ง์ ๊ตฌ๋ถ์๋ฅผ ๋ฌ์์ค์ผํด์ ๋ฒ๊ฑฐ๋กญ์ง๋ง, @Primary๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณ๋ค๋ฅธ ์ถ๊ฐ์์ ์์ด ์ํ๋ ์์กด๊ด๊ณ๋ฅผ ์ค์ ํ ์ ์๋ค.
@Component @Primary public class RateDiscountPolicy implements DiscountPolicy {} @Component public class FixDiscountPolicy implements DiscountPolicy {}
@ Primary์ Qualifier์ ํ์ฉํ
์ฝ๋์์ ์์ฃผ ์ฌ์ฉํ๋ ๋ฉ์ธ DB ์ปค๋ฅ์ ์ ํ๋ํ๋ ์คํ๋ง๋น๊ณผ, ํน๋ณํ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ค๊ณ ๊ฐ๋์ ์ฌ์ฉํ๋ ์๋ธ DB์ ์ปค๋ฅ์ ์ ํ๋ํ๋ ์คํ๋ง ๋น์ด ๊ฐ๊ฐ ์๋ค๊ณ ์๊ฐํด๋ณด์. ๋ฉ์ธ DB๋น์ @Primary๋ฅผ ์ ์ฉํด์ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ๊ณ ๊ฐ๋ ์ฌ์ฉํ๋ ์๋ธDB๋ @Qualifier๋ฅผ ์ง์ ํ์ฌ ๋ช ์์ ์ผ๋ก ํ๋ํ๋ ๋ฐฉ์์ด ์ฝ๋๋ฅผ ๊น๋ํ๊ฒ ์ ์งํ๋ฉด์, ๊ฐ๋ฐ์์ ์ค์๋ฅผ ๋ฏธ์ฐ์ ๋ฐฉ์งํด์ค๋ค. (๋ฌผ๋ก ์ด๋ ์ฌ์ฉํ๊ธฐ ๋๋ฆ์ด๋ค. ํ์์ ๋ฐ๋ผ ์ ๋ถ @Qualifier๋ก ํด๋ ์ ํ ๋ฌธ์ ๊ฐ ์๋ค.)
* ์ฐธ๊ณ ๋ก ๋ค๋ฅธ ์ฐ์ ์์์ ๋ง์ฐฌ๊ฐ์ง๋ก, ๋์์ ์ฌ์ฉํ์ ๊ฒฝ์ฐ ๊ธฐ๋ณธ๊ฐ์ฒ๋ผ ๋์ํ๋ @Primary๋ณด๋ค ์ง์ ์ง์ ํด์ฃผ๋ @Qualifier๊ฐ ์ฐ์ ๊ถ์ด ๋๋ค.
@ ์ปดํ์ผ์ ํ์ ์ฒดํฌ (์ด๋ ธํ ์ด์ )
@Qualifier("mainDiscountPolicy") ์ด๋ ๊ฒ ์ฌ์ฉํ๋ ๋ฐฉ์์ 'mainDiscountPolicy'๋ผ๋ ๋ฌธ์๋ ์ปดํ์ผ์ ์ฒดํฌ๊ฐ ๋ถ๊ฐ๋ฅํ๋ค. ์ฆ ํ์ ์ฒดํฌ๊ฐ ์๋๋ค. ์ด๋ ๋ค์๊ณผ ๊ฐ์ ์ด๋ ธํ ์ด์ ์ผ๋ก ๊ฐ์ธ์ ์ฌ์ฉํ๋ฉด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Qualifier("mainDiscountPolicy") public @interface MainDiscountPolicy { }
@Component @MainDiscountPolicy // ์ด๋
ธํ
์ด์
์ ์ฌ์ฉํ๋ ๊ฒ ๋ ๋์ ๋ฐฉ๋ฒ์ด๋ค. public class RateDiscountPolicy implements DiscountPolicy {}
@Autowired public OrderServiceImpl(MemberRepository memberRepository, @MainDiscountPolicy DiscountPolicy discountPolicy){ this.memberRepository=memberRepository; this.discountPolicy=discountPolicy; }
๋ค๋ง Qualifier ์ฒ๋ผ ํน๋ณํ ๋ชฉ์ ์ด ์๋๊ฒ ์๋๋ผ๋ฉด, ๋ณดํต์ ์๋ก ์ด๋ ธํ ์ด์ ์ ๋ง๋ค์ง ๋ง๊ณ ์คํ๋ง์์ ์ ๊ณตํ๋ ๊ธฐ๋ณธ ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋๊ฒ ๊น๋ํ๊ณ ์ ์ง๋ณด์์ ์ข๋ค.
# ์กฐํํ ๋น์ด ๋ชจ๋ ํ์ํ ๋ (List, Map)
์์ ์์ ์์ ํ ์ธ์ ์ฑ ์ ํด๋ผ์ด์ธํธ๊ฐ ์กด์ฌํ๋ ํ ์ธ์ ์ฑ ์ค์ ํ๋๋ฅผ ์ ํํ ์ ์๋ค๊ณ ์๊ฐํด๋ณด์. ์คํ๋ง์ ์ฌ์ฉํ๋ฉด ์ด์ ๊ฐ์ ์ ๋ต ํจํด์ ์๋ฐ์ Map๊ณผ List๋ก ๋งค์ฐ ๊ฐ๋จํ๊ฒ ๊ตฌํํ ์ ์๋ค.
class DiscountService { private final Map<String, DiscountPolicy> policyMap; private final List<DiscountPolicy> policies; // Map ๋๋ List๋ก ๋ชจ๋ DiscountPolicy ๋น์ ์ฃผ์
๋ฐ๋๋ค. // ๋ณดํต ๋ ์ค ํ๋๋ง ์ฌ์ฉํ์ง๋ง, ์์ ๋ก ๋ณด์ฌ์ค๋ ค๊ณ Map, List๋ก ๊ฐ๊ฐ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์
๋ฐ์๋ค. @Autowired public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) { this.policyMap = policyMap; this.policies = policies; } public int discount(Member member, int price, String discountCode) { DiscountPolicy discountPolicy = policyMap.get(discountCode); return discountPolicy.discount(member, price); } }
@Autowired๋ฅผ ์ฌ์ฉํด์ ์์กด๊ด๊ณ๋ฅผ Map์ด๋ List๋ก ๋ฐ๊ฒ๋๋ฉด ํด๋นํ๋ ๋ชจ๋ Bean๋ค์ด ๋ค์ด๊ฐ๊ฒ ๋๋ค. ์ด๋ฅผ ์ด์ฉํ๋ฉด ์๋์ ๊ฐ์ ์ ๋ตํจํด(์กด์ฌํ๋ ํ ์ธ์ ์ฑ ์ค์ ํ๋๋ฅผ ์ ํ)์ ๊ตฌํํ ์ ์๋ค. ์ด๋ฅผ ์คํ๋ง ์์ด ๊ตฌํํด๋ณด๋ฉด ์๊ฒ ์ง๋ง, ์์ฑํด์ผํ ์ฝ๋๊ฐ ์ ๋ง ๋ง์๋ฐ ์คํ๋ง์ ์๋ ์์กด๊ด๊ณ ์ฃผ์ ์ ํ์ฉํ๋ฉด ์ ๋ง ๊ฐ๋จํ๊ฒ ๊ตฌํํ ์ ์๋ค.
public class AllBeanTest { @Test void findAllBean() { // ์คํ๋ง ๋น ์์ฑ. ์์ง Map๊ณผ List๋ ๋น์ด์๋ค. (์์กด์ฑ ์ฃผ์
X) ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class); // ์๋ ์์กด๊ด๊ณ ์์ฑ์ ์ฃผ์
์ ์ด์ฉํ๋ค. // DiscountService์ ์๋ Map๊ณผ List์ DiscountPolicy๋ค์ด ์ฑ์์ ธ ์๋ค. (fix, rate) DiscountService discountService = ac.getBean(DiscountService.class); // discount() ๋ฉ์๋๋ "fixDiscountPolicy" ๊ฐ ๋์ด์ค๋ฉด map์์ ํด๋น ์ด๋ฆ์ ๋น์ ์ฐพ์ ์คํํ๋ค. Member member = new Member(1L, "userA", Grade.VIP); int discountPrice = discountService.discount(member, 10000,"fixDiscountPolicy"); assertThat(discountService).isInstanceOf(DiscountService.class); assertThat(discountPrice).isEqualTo(1000); } }
# ์๋๊ณผ ์๋, ์ฌ๋ฐ๋ฅธ ์ ํ์ ๊ธฐ์ค
์คํ๋ง ํ๋ ์์ํฌ๋ ์ ๋ฐ์ดํธ๋ฅผ ๊ณ์ํ๋ฉฐ ๋ง์ ๋ถ๋ถ์ ์๋์ผ๋ก ์ฒ๋ฆฌํ ์ ์๊ฒ ๋ง๋ค์ด์ฃผ๊ณ ์๋ค. ๊ทธ๋ ๋ค๊ณ ์ ๋ถ ์๋์ผ๋ก ์ฌ์ฉํ๊ฒ๋๋ฉด ํ๋ก์ ํธ์ ๊ตฌ์กฐ๋ฅผ ํ์ ํ๊ธฐ ํ๋ค๊ณ ๋ฌธ์ ๊ฐ ์๊ฒผ์ ๋ ์ฐพ๊ธฐ ํ๋ค ๊ฒ ๊ฐ์๋ฐ, ์ด๋๊น์ง ์๋์ผ๋ก ์ฌ์ฉํด์ผ ํ ๊น?
๊ฒฐ๋ก ๋ถํฐ ์ด์ผ๊ธฐํ๋ฉด, ์ ๊ณตํ๋ ํธ๋ฆฌํ ์๋ ๊ธฐ๋ฅ์ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํ๋ค. ์คํ๋ง์ @Component ๋ฟ๋ง ์๋๋ผ @Controller, @Service, @Repository ์ฒ๋ผ ๊ณ์ธต์ ๋ง์ถ์ด ์ผ๋ฐ์ ์ธ ์ฑ ๋ก์ง์ ์๋์ค์บ ํ ์ ์๋๋ก ์ง์ํ๋ค. ๊ฑฐ๊ธฐ์ ๋ํด 2014๋ ์คํ๋ง ๋ถํธ์ ๋ฑ์ฅ์ผ๋ก ์ปดํฌ๋ํธ ์ค์บ์ด ์ค์ ์ด ์๋ ๊ธฐ๋ณธ ๋์์ผ๋ก ๋ฐ๋๊ฒ ๋์๊ณ , ์คํ๋ง ๋ถํธ์ ๋ค์ํ ๋น๋ค๋ ์กฐ๊ฑด์ด ๋ง์ผ๋ฉด ์๋์ผ๋ก ๋ฑ๋กํ๋๋ก ์ค๊ณ๋์ด์ ธ์๋ค.
๋ฌผ๋ก ์ค์ ์ ๋ณด(AppConfig)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์คํ๋ถ๋ถ๊ณผ ๊ตฌ์ฑ๋ถ๋ถ์ ๋ช ํํ๊ฒ ๋๋๋ ๊ฒ์ด ์ด์์ ์ด๊ธด ํ๋ค. ํ์ง๋ง ๊ฐ๋ฐ์ ์ ์ฅ์์ @Component ๋ง ์ ์ด์ฃผ๋ฉด ๋๋๋ ์ผ์ ํ๋ํ๋ ์ง์ ํด์ฃผ๋๊ฑด ์๋นํ ๋ฒ๊ฑฐ๋กญ๊ธฐ๋ ํ๊ณ , ๊ด๋ฆฌํ ๋น์ด ๋ง์์ง๋ฉด ์ค์ ์ ๋ณด๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ ์์ฒด๊ฐ ๋ถ๋ด์ด ๋๋ค. ๊ฒฐ์ ์ ์ผ๋ก ์๋ ๋น์ ์ฌ์ฉํด๋ OCP, DIP๋ฅผ ์งํฌ ์ ์๋ค.
@ ๊ทธ๋ผ ์๋ ๋น์ ์ธ์ ์ฐ๋์?
๋ณดํต ์ดํ๋ฆฌ์ผ์ด์ ์ ์ ๋ฌด ๋ก์ง(๋น์ฆ๋์ค)์ ๊ธฐ์ ์ง์ ๋ก์ง์ผ๋ก ๋๋ ์ ์๋ค.
- ์ ๋ฌด๋ก์ง ๋น : ์น์ ์ง์ํ๋ ์ปจํธ๋กค๋ฌ, ํต์ฌ ๋น์ฆ๋์ค ๋ก์ง์ ๊ฐ์ง ์๋น์ค, ๋ฐ์ดํฐ ๊ณ์ธต์ ๋ฆฌํฌ์งํ ๋ฆฌ ๋ฑ์ด ๋ชจ๋ ์ ๋ฌด ๋ก์ง์ ํด๋น๋๋ค. ๋ณดํต ๋น์ฆ๋์ค ์๊ตฌ์ฌํญ์ ๊ฐ๋ฐํ ๋ ๋ณ๊ฒฝ๋๋ค.
- ๊ธฐ์ ์ง์ ๋น : ๊ธฐ์ ์ ์ธ ๋ฌธ์ ๋ ๊ณตํต ๊ด์ฌ์ฌ(AOP)๋ฅผ ์ฒ๋ฆฌํ ๋ ์ฃผ๋ก ์ฌ์ฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ, ๊ณตํต ๋ก๊ทธ์ฒ๋ฆฌ ์ฒ๋ผ ๋น์ฆ๋์ค ์๊ตฌ์ฌํญ ๊ทธ ์์ฒด๋ผ๊ธฐ ๋ณด๋ค๋, ์ ๋ฌด ๋ก์ง์ ์ง์ํ๊ธฐ ์ํ ํ๋ถ ๊ธฐ์ ๋ค์ด๋ค.
์ ๋ฌด ๋ก์ง ๋น์ ๋ง๋ค ๋์๋ ์๋๊ธฐ๋ฅ์ ์ ๊ทน ์ฌ์ฉํ์. ์ ์ด์ ๊ด๋ฆฌํด์ผํ ์ฝ๋๊ฐ ๋๋ฌด ๋ง์ ๊ทธ๋ฐ ๊ฒ๋ ์์ง๋ง ์ปจํธ๋กค๋ฌ-์๋น์ค-๋ฆฌํฌ์งํ ๋ฆฌ์ฒ๋ผ ์ด๋์ ๋ ์ ์ฌํ ํจํด์ด ์กด์ฌํ๋ค. ์ด๋ฐ ๊ฒฝ์ฐ ๋ฌธ์ ๊ฐ ์๊ธฐ๋๋ผ๋ ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋์ง ๋ช ํํ๊ฒ ํ์ ํ๊ธฐ ์ฝ๋ค. (์ด๋ ์๋น์ค์์ ๋ฌธ์ ๊ฐ ๋ฌ๋์ง ์ฐพ๊ธฐ ์ฝ๋ค.)
๋ฐ๋๋ก ๊ธฐ์ ์ง์ ๋ก์ง์ ์ ๋ฌด ๋ก์ง๊ณผ ๋น๊ตํด์ ์๊ฐ ์ ๊ณ , ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ฐ์ ๊ฑธ์ณ ๊ด๋ฒ์ํ๊ฒ ์ํฅ์ ๋ผ์น๊ฒ ๋๋ค. ๊ทธ๋์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋๋ผ๋ ์ ํํ๊ฒ ์ด๋๊ฐ ๋ฌธ์ ์ธ์ง ์๊ธฐ ์ด๋ ต๊ณ , ์ ์ฉ์ด ์๋์๋์ง ์กฐ์ฐจ ํ์ ํ๊ธฐ ๊น๋ค๋กญ๋ค. ์ด๋ฌํ ๋ก์ง๋ค์ ๊ฐ๊ธ์ ์๋ ๋น ๋ฑ๋ก์ ํ์ฉํ์ฌ ์ฌ์ฉํ๊ณ ์์์ ๋ช ํํ๊ฒ ๋ค์ด๋ด๋ ๊ฒ์ด ์ข๋ค.
@ ๋น์ฆ๋์ค ๋ก์ง์์ ์๋ ๋น์ ํตํ ๋คํ์ฑ์ ํ์ฉ
์์์ ์ฌ์ฉํ๋ ์ ๋ตํจํด์ ์๊ฐํด๋ณด์. ์๋ ์ฝ๋๋ฅผ ํ๋์ ๋ณด๊ณ ์ด๋ ํ ๋์์ ํ๋์ง ์์ ์์๊น?
class DiscountService { private final Map<String, DiscountPolicy> policyMap; private final List<DiscountPolicy> policies; // Map ๋๋ List๋ก ๋ชจ๋ DiscountPolicy ๋น์ ์ฃผ์
๋ฐ๋๋ค. // ๋ณดํต ๋ ์ค ํ๋๋ง ์ฌ์ฉํ์ง๋ง, ์์ ๋ก ๋ณด์ฌ์ค๋ ค๊ณ Map, List๋ก ๊ฐ๊ฐ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์
๋ฐ์๋ค. @Autowired public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) { this.policyMap = policyMap; this.policies = policies; } public int discount(Member member, int price, String discountCode) { DiscountPolicy discountPolicy = policyMap.get(discountCode); return discountPolicy.discount(member, price); } }
์ด๋ฐ ๊ฒฝ์ฐ ํด๋น ๋ถ๋ถ์ ์๋์ ๊ฐ์ด ์๋์ผ๋ก ๋ฑ๋กํ์ฌ ํ๋์ ์๋ฏธ๋ฅผ ์ ์ ์๋๋ก ํด์ฃผ๋ ๊ฒ๋ ๋์์ง ์๋ค. ๋ํ ์๋์ผ๋ก ์ฌ์ฉํ๋๋ผ๋ ์ต์ํ 'ํน์ ํจํค์ง'์ ํ๋๋ก ๋ฌถ์ด์ ์๋ฏธ๋ฅผ ์ฝ๊ฒ ์ฐพ์ ์ ์๋๋ก ๋ง๋ค์ด์ฃผ์.
@Configuration public class DiscountPolicyConfig { @Bean public DiscountPolicy rateDiscountPolicy() { return new RateDiscountPolicy(); } @Bean public DiscountPolicy fixDiscountPolicy() { return new FixDiscountPolicy(); } }
@ ๋จ, ์คํ๋ง๊ณผ ๋ถํธ๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ์๋ ๋ฑ๋กํ๋ ๋น์ ์์ธ์ด๋ค.
์คํ๋ง๋ถํธ์ ๊ฒฝ์ฐ DataSource ๊ฐ์ DB์ฐ๊ฒฐ์ ์ฌ์ฉ๋๋ ๊ธฐ์ ์ง์ ๋ก์ง๊น์ง ์๋์ผ๋ก ๋ฑ๋กํ๋๋ฐ, ์ด๋ฐ ๋ถ๋ถ์ ๋ฉ๋ด์ผ์ ์ ์ฐธ๊ณ ํด์ ์คํ๋ง๋ถํธ๊ฐ ์๋ํ ๋๋ก ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ๋ฉด ๋๋ค.
๋ง์ฝ ์คํ๋ง๋ถํธ๊ฐ ์๋๋ผ ๋ด๊ฐ ์ง์ ๊ธฐ์ ์ง์ ๊ฐ์ฒด๋ฅผ ๋น์ผ๋ก ๋ฑ๋กํ๋ค๋ฉด, ์ด๋ ์๋์ผ๋ก ๋ฑ๋กํด์ ์๋ฏธ๋ฅผ ๋ช ํํ๊ฒ ๋๋ฌ๋ด์ฃผ์.
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev