#8 ์ปดํฌ๋ํธ ์ค์บ๊ณผ ์์กด๊ด๊ณ ์๋์ฃผ์
by JiwonDevํด๋น ๊ธ์ ๊น์ํ๋์ ์ธํ๋ฐ ๊ฐ์๋ฅผ ๊ณต๋ถํ๊ณ ์ ๋ฆฌํ ๋ด์ฉ์ ๋๋ค.
# ์ปดํฌ๋ํธ ์ค์บ?
์์์ ์คํ๋ง ๋น์ ๋ฑ๋กํ ๋ Java ์ด๋ ธํ ์ด์ ์ฝ๋ (@Bean)์ด๋ XML <bean>๋ฑ์ ํตํด ์ค์ ์ ๋ณด์ ์ง์ ๋ฑ๋กํ ์คํ๋ง ๋น์ ์ง์ ํด์ฃผ์๋ค. ํ์ง๋ง ์ด ์์ ์ ํ๋ก์ ํธ๊ฐ ์ปค์ง๋ฉด ์ผ์ผ์ด ํ๋ํ๋ ์ ์ด์ฃผ๊ธฐ๋ ๋ฒ๊ฑฐ๋ฝ๊ณ , ์์ ํ ๋ ๋๋ฝ๋๋ ๊ฒฝ์ฐ๋ ์์ฃผ ๋ฐ์ํ๋ค.
๊ทธ๋์ ์คํ๋ง์ ์ค์ ์ ๋ณด๊ฐ ์์ด๋ ์๋์ผ๋ก ์คํ๋ง ๋น์ ๋ฑ๋กํด์ฃผ๋ ์ปดํฌ๋ํธ ์ค์บ์ด๋ผ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค. ๋ ๋๋์ด ๋งจ๋ ๋ณด๋ @Autowired ๋ผ๋ ์์กด๊ด๊ณ๋ฅผ ์๋์ผ๋ก ์ฃผ์ ํด์ฃผ๋ ๊ธฐ๋ฅ๋ ์ ๊ณตํ๋ค.
# ์ปดํฌ๋ํธ ์ค์บ์ ์ฌ์ฉํด๋ณด์
๊ฐ๋จํ๋ค. @ComponentScan ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ ์ฌ์ฉํ ์ ์๋ค. ์ฐธ๊ณ ๋ก ์ปดํฌ๋ํธ ์ค์บ์ ํ๊ฒ๋๋ฉด @Configuration์ด ๋ถ์ ์ค์ ์ ๋ณด๋ ์๋์ผ๋ก ๋ฑ๋ก๋๋ค. @Configuration ๋ด๋ถ์ @Componet๊ฐ ์ ์ธ๋์ด ์๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋์ ์์ ์์ ์ ์ ์ค์ ์ ๋ณด๋ฅผ ์ปดํฌ๋ํธ ์ค์บ์ ์ ์ธํ๊ธฐ ์ํด excludeFilter๋ฅผ ์ฌ์ฉํ์ฌ ์๋์ ๊ฐ์ด ์ ์ด์ฃผ์๋ค. (* ๋ณดํต์ ๊ตณ์ด ์ค์ ์ ๋ณด๋ฅผ excludeFilter๋ก ์ฌ์ฉํ์ง ์๊ณ , ๊ทธ๋ฅ ์ปดํฌ๋ํธ ์ค์บ์ ์ฌ์ฉํ๋ค.)
@Configuration @ComponentScan(excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Configuration.class)) public class AutoAppConfig { // ์๋ตํ๊ฒ ์๋๋ค. ๋ฑ๋กํ ํด๋์ค๊ฐ ํ๋๋ ์๋ค. }
์ปดํฌ๋ํธ ์ค์บ์ ๋ฑ๋กํ๋ค๋ฉด, ์๋์ ๊ฐ์ด ๊ฐ๊ฐ์ ํด๋์ค์ @Component ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ์ฃผ์.
@Component public class MemoryMemberRepository implements MemberRepository { public static Map<Long, Member> store = new HashMap<>(); @Override public void save(Member member) { store.put(member.getId(), member); } @Override public Member findById(Long memberId) { return store.get(memberId); } }
@Component public class RateDiscountPolicy implements DiscountPolicy { private int discountPercent = 10; @Override public int discount(Member member, int price) { if (member.getGrade() == Grade.VIP) { return price * discountPercent / 100; } return 0; } }
์์๋ ์ธ๊ธํ๋ค์ถ์ด @Autowired๋ฅผ ์ฌ์ฉํ๋ฉด ์์กด๊ด๊ณ๋ฅผ ์๋์ผ๋ก ์ฃผ์ ํ ์ ์๋ค. ์ฆ ์์์ AppConfig์์ ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด๋ฅผ ๋ฃ์ด์ฃผ๋ ๊ณผ์ ์ ์ปดํฌ๋ํธ๋ฅผ ์ค์บํ์ฌ ์๋์ผ๋ก ์ฒ๋ฆฌ ํด์ค๋ค. (๋ค๋ฅธ ๊ธฐ๋ฅ๋ ์๋๋ฐ, ์ด๋ ๋์ค์ ์ถ๊ฐ๋ก ์ค๋ช ํ๊ฒ ๋ค.)
@Component public class MemberServiceImpl implements MemberService { private final MemberRepository memberRepository; @Autowired public MemberServiceImpl(MemberRepository memberRepository) { this.memberRepository = memberRepository; } @Override public void join(Member member) { memberRepository.save(member); } @Override public Member findMember(Long memberId) { return memberRepository.findById(memberId); } }
์ปดํฌ๋ํธ ์ค์บ์ด ์ ๋ง ์ ๋๋ก ๋์ํ๋์ง ํ ์คํธ์ฝ๋๋ฅผ ํตํด ์์๋ณด์.
public class AutoAppConfigTest { @Test void basicScan() { ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class); MemberService memberService = ac.getBean(MemberService.class); assertThat(memberService).isInstanceOf(MemberService.class); } }

# ์ปดํฌ๋ํธ ์ค์บ์ ๋์๊ณผ์
@ComponentScan์ ์ค์ ํ๋ฉด, @Component๊ฐ ๋ถ์ ๋ชจ๋ ํด๋์ค๋ฅผ ์๋์ผ๋ก ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๋ค. ์ด์ ์ฒ๋ผ AppConfig์์ ์์กด๊ด๊ณ ์ฃผ์ ๋ฉ์๋์ ํ๋ํ๋ @Bean์ ๋ถ์ฌ์ฃผ์ง ์์๋ ๋๋ค. (@Configuration ์ฒ๋ผ ํด๋น ํ๊ทธ ๋ด๋ถ์ @Component๊ฐ ์ ์ธ๋์ด ์๋ ํด๋์ค๋ ์์ฑ ๋์์ด ๋จ์ ์ ์ํ์.)

๊ทธ๋ฆฌ๊ณ ์์ฑ์์ @Autowired๋ฅผ ์ง์ ํ๋ฉด, ์๋์ ๊ฐ์ด AppConfig์ @Bean ๋ฉ์๋์์ ์์กด๊ด๊ณ๋ฅผ ํ๋ํ๋ ์ฃผ์ ํด์ฃผ๋ ๊ฒ์ ๋์ ํด์ค๋ค.
//* @ComponentScan ์ผ๋ก ๋น ๋ฑ๋ก, @Autowired๋ก ์์กด๊ด๊ณ๋ฅผ ์ฃผ์
ํ ์ฝ๋ * @Configuration @ComponentScan(excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Configuration.class)) public class AutoAppConfig { // ์๋ตํ๊ฒ ์๋๋ค. ๋ฑ๋กํด์ผํ๋ ํด๋์ค๊ฐ ํ๋๋ ์๋ค. }
//* ๊ธฐ์กด์ ์ฝ๋ * @Configuration // ๊ตฌํ์ฒด๋ฅผ ์ฑ๊ธํค ๊ฐ์ฒด๋ก ์ ์ง์์ผ์ฃผ๋ ํ๊ทธ. public class AppConfig { @Bean // memoryRepository ์์กด๊ด๊ณ ์ฃผ์
public MemberRepository memberRepository() { return new MemoryMemberRepository(); } @Bean // memberService์ ์์กด๊ด๊ณ ์ฃผ์
. public MemberService memberService() { return new MemberServiceImpl(memberRepository()); } @Bean // OrderService์ ์์กด๊ด๊ณ ์ฃผ์
. public OrderService orderService() { return new OrderServiceImpl( memberRepository(), discountPolicy()); } ... ์๋ต ... }
@Autowired์ ์๋ฆฌ๋ ์คํ๋ง ์ปจํ ์ด๋๊ฐ [๋ฑ๋ก๋ ์คํ๋ง ๋น]์ค์์ ํ์ ์ด ๊ฐ์ ๋น์ ์ฐพ์ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์ ํ๋ค. ๊ธฐ๋ณธ ๋์์ ๊ฐ์ ํ์ ์ ๋น์ ์กฐํํ๋ getBean(MemberRepositoryt.class) ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ memoryMemberRepository๋ฅผ ์ฐพ์ ๋ฑ๋กํด์ฃผ๋ ๋ฐฉ์์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋ค.

# ์ปดํฌ๋ํธ ํ์ ์์น์ง์
@ComponentScan๋ ํ๋ก์ ํธ ๋ด์ ๋ชจ๋ ์๋ฐ ํด๋์ค, ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ค์ ธ์ @Component๋ฅผ ์ฐพ์ ์ค์บํ๋ค. ์ด ๊ณผ์ ์ ์๊ฐ์ด ์ค๋๊ฑธ๋ฆฌ๊ฒ ๋๋๋ฐ, basekPackages ์ต์ ์ ์ด์ฉํ์ฌ ํ์ํ ์์น๋ฅผ ์ง์ ํด์ค ์ ์๋ค.
- basePackages : ํ์ํ ํจํค์ง์ ์์ ์์น๋ฅผ ์ง์ ํ๋ค. ์ด ํจํค์ง๋ฅผ ํฌํจํ ํ์ ํจํค์ง๋ฅผ ๋ชจ๋ ํ์ํ๋ค.
- basePackages = {"hello.core", "hello.service"} ์ฒ๋ผ ์ฌ๋ฌ ๊ฐ๋ฅผ ์ง์ ํด์ค ์ ์๋ค. ๋์์ ๋์ผํ๋ค.
- basePackageClasses : ์ง์ ํ ํด๋์ค๊ฐ ์ํ ํจํค์ง๋ฅผ ํ์ ์์์์น๋ก ์ง์ ํ๋ค.
(=> ์ง์ ํ์ง ์์ผ๋ฉด @ComponentScan์ด ๋ถ์ ์ค์ ํด๋์ค๊ฐ ์์์์น๊ฐ ๋๋ค.)
์คํ๋ง์์ ๊ถ์ฅํ๋ ๋ฐฉ๋ฒ์, ์ค์ ํด๋์ค(AppConfig)๋ฅผ ํ๋ก์ ํธ ์์ ๋ฃจํธ์ ๋๊ณ ์ง์ ํ์ง ์๊ณ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค. ( ์คํ๋ง ๋ถํธ๋ฅผ ์ฌ์ฉํ๋ฉด @SpringBootApplication์ ์ฑ ์์์ ๋๋๊ฒ ์ผ๋ฐ์ ์ธ๋ฐ, ํด๋น ํ๊ทธ ์์ @ComponentScan์ด ํฌํจ๋์ด ์๊ธฐ ๋๋ฌธ์ด๊ธฐ๋ ํ๋ค.)
@ComponentScan( basePackages = "hello.core" )

# ์ปดํฌ๋ํธ ์ค์บ ๊ธฐ๋ณธ๋์
์ฐธ๊ณ ๋ก @ComponentScan์ @Component ๋ฟ๋ง ์๋๋ผ ์๋์ ํ๊ทธ๋ค๋ ์๋ ์ค์บ๋์์ ์ถ๊ฐํ๋ค. (์ด๋ ํด๋น ํ๊ทธ ์์ @Component ํ๊ทธ๋ฅผ ํฌํจํ๊ณ ์๊ธฐ ๋๋ฌธ์ด๋ค.)
- @Component : ์ปดํฌ๋ํธ ์ค์บ์์ ์ฌ์ฉ
- @Configuration : ์คํ๋ง ์ค์ ์ ๋ณด์์ ์ฌ์ฉ
- @Controller : ์คํ๋ง MVC ์ปจํธ๋กค๋ฌ์์ ์ฌ์ฉ + ์คํ๋ง MVC ์ปจํธ๋กค๋ฌ๋ก ์ธ์ํจ.
- @Repository : ์คํ๋ง ๋ฐ์ดํฐ ์ ๊ทผ ๊ณ์ธต์์ ์ฌ์ฉ + DB์์ ํฐ์ง ์์ธ๋ฅผ ์คํ๋ง ์์ธ๋ก ์ถ์ํํด์ ๋ณํํด์ค.
- @Service : ์คํ๋ง ๋น์ฆ๋์ค ๋ก์ง์์ ์ฌ์ฉ + ํน๋ณํ ์ฒ๋ฆฌ๋ ์์. ๊ทธ๋ฅ ๋น์ฆ๋์ค ๋ก์ง์์ ๋ํ๋ด๊ธฐ ์ํจ.
* ํ๋ฒ ์ธ๊ธํ๊ณ ๋์ด๊ฐ์๋ฉด, ์ด๋ ธํ ์ด์ ์ 'Java'์ ๊ธฐ๋ฅ์ด์ง๋ง ์ด๋ฅผ ์์ํ๋ฏ์ด ์ฌ์ฉํ๋ ๊ฑด '์คํ๋ง ํ๋ ์์ํฌ'์์ ์ง์ํ๋ ๊ธฐ๋ฅ์ด๋ค. ์ฆ ์ปค์คํ ์ด๋ ธํ ์ด์ ํ๊ทธ๋ฅผ ๋ง๋ค ์๋ ์๊ณ , ์คํ๋ง์ ์ต์ (userDefaultFilters)์ ๋ฐ๊ฟ ๊ธฐ๋ณธ ์ค์บ๋์์ ๋ชจ๋ ์ ์ธํ ์๋ ์๋ค.
# ์ค์บ๋์ ํํฐ
์์์๋ ์ธ๊ธํ์ง๋ง, @ComponentScan์ ์๋ ์ต์ ์ ํตํด ์ค์บ๋์์ ์ ์ธ/์ถ๊ฐ์ง์ ํด์ค ์ ์๋ค. ํํฐ์ ์ ํํ ์ฌ์ฉ๋ฐฉ๋ฒ์ ์คํ๋ง ์ด๋ ธํ ์ด์ ์ ์์์ผ ํ๋ฏ๋ก, ์ผ๋จ ์๋์ ๊ฐ์ด ๊ฐ๋ฅํ๋ค๋๊ฑฐ๋ง ์๊ณ ๋์ด๊ฐ์.
- includeFilters : ์ปดํฌ๋ํธ ์ค์บ ๋์์ ์ถ๊ฐ๋ก ์ง์ ํ๋ค.
- excludeFilters : ์ปดํฌ๋ํธ ์ค์บ์์ ์ ์ธํ ๋์์ ์ง์ ํ๋ค.
@Configuration @ComponentScan( includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class), excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class) ) class ComponentFilterAppConfig {}
@Filter์ type ๊ธฐ๋ณธ๊ฐ์ ANNOTATION์ผ๋ก ํด๋น ์ด๋ ธํ ์ด์ ์ ์ธ์ํด์ ๋์ํ๋๋ก ๋์ด์๋ค. ์ ์ฌ์ฉํ ์ผ์ ์์ง๋ง ํน์ ํด๋์ค๋ ์ ๊ทํํ์์ ํํฐ์กฐ๊ฑด์ผ๋ก ๋ฃ์ด์ค ์๋ ์๋ค. ์๋ฅผ ๋ค์ด BeanA๋ผ๋ ํด๋์ค๋ฅผ ์ ์ธํ๊ณ ์ถ์ผ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ๋ฉด ๋๋ค. @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = BeanA.class)

import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyIncludeComponent { // ์ปดํฌ๋ํธ ์ค์บ์ ์ถ๊ฐํ๊ณ ์ถ์ ์ด๋
ธํ
์ด์
์ ์ } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyExcludeComponent { // ์ปดํฌ๋ํธ ์ค์บ์ ์ ์ธํ๊ณ ์ถ์ ์ด๋
ธํ
์ด์
์ ์ } @MyIncludeComponent public class BeanA { // ์ปดํฌ๋ํธ ์ค์บ์ ์ถ๊ฐํ๊ณ ์ถ์ ํด๋์ค } @MyExcludeComponent public class BeanB { // ์ปดํฌ๋ํธ ์ค์บ์ ์ ์ธํ๊ณ ์ถ์ ํด๋์ค }
์๋์ ๊ฐ์ ํ ์คํธ ์ฝ๋๋ฅผ ํตํด ํด๋น ์ปดํฌ๋ํธ๊ฐ ์ ๋๋ก ๋ฑ๋ก/์ ์ธ ๋์๋์ง๋ ํ์ธํด๋ณด์.
public class ComponentFilerAppConfigTest { @Test void filterScan() { ApplicationContext ac = new AnnotationConfigApplicationContext(ComponentFilterAppConfig.class); BeanA beanA = ac.getBean("beanA", BeanA.class); assertThat(beanA).isNotNull(); Assertions.assertThrows( NoSuchBeanDefinitionException.class, () -> ac.getBean("beanB", BeanB.class)); } // ํ
์คํธ์ฉ AppConfig ์ด๋ฆ -> ComponentFilterAppConfig @Configuration @ComponentScan( includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class), excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class) ) static class ComponentFilterAppConfig {} }
# ์ปดํฌ๋ํธ ์ค๋ณต ๋ฑ๋ก๊ณผ ์ถฉ๋
๋น ์ด๋ฆ์ ๊ฐ๊ฒ ๋ฑ๋กํ๊ฒ๋๋ฉด ๋ฎ์ด์์์ง๊ฑฐ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์๋ค๊ณ ์์์ ๋ฐฐ์ ๋ค. ์ปดํฌ๋ํธ ์ค์บ์์ ๊ฐ์ ๋น ์ด๋ฆ์ ๋ฑ๋กํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น? ์๋ ๋ ๊ฐ์ง ์ํฉ์ ์๊ฐํด๋ณด์.
@์๋ ๋น ๋ฑ๋ก vs ์๋ ๋น ๋ฑ๋ก
์ด๋ ๊ฐ๋จํ๋ค. ์ปดํฌ๋ํธ ์ค์บ์ ์ํด ๋ฑ๋ก๋๋ค๊ฐ ์ด๋ฆ์ด ๊ฐ์ ๋น์ ๋ฐ๊ฒฌํ ๊ฒฝ์ฐ ์คํ๋ง์ ์์ธ(ConflictingBeanDefinitionException)๋ฅผ ๋ฐ์์ํจ๋ค.
@์๋ ๋น ๋ฑ๋ก vs ์๋ ๋น ๋ฑ๋ก
๊ทธ๋ ๋ค๋ฉด ๋ด๊ฐ ์ง์ ํ ๋น๊ณผ ์๋์ผ๋ก ๋ง๋ค์ด์ง ๋น ์ด๋ฆ์ด ๊ฒน์น๋ค๋ฉด? ์ด ๊ฒฝ์ฐ ์๋์ผ๋ก ๋ฑ๋กํ ๋น์ด ์๋์ผ๋ก ๋ฑ๋กํ ๋น์ ์ค๋ฒ๋ผ์ด๋ฉ ํด๋ฒ๋ฆฐ๋ค.
// ์๋, ์ปดํฌ๋ํธ ์ค์บ @Component public class MemoryMemberRepository implements MemberRepository {}
// ์๋์ผ๋ก @Bean ๋ฑ๋ก ๋ฐ ์์กด๊ด๊ณ ์์ฑ @Configuration @ComponentScan( excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Configuration.class) ) public class AutoAppConfig { @Bean(name = "memoryMemberRepository") public MemberRepository memberRepository() { return new MemoryMemberRepository(); } }
์ค์ ์คํ๋ง ์ฝ์์ฐฝ์์ ๋ค์๊ณผ ๊ฐ์ด ์ค๋ฒ๋ผ์ด๋ฉ ๋์์์ ๋ฉ์์ง๋ก ์๋ ค์ค๋ค. ์๋์ ์ผ๋ก ์ด๋ ๊ฒ ํ๋ค๋ฉด ๋คํ์ด์ง๋ง, ๋ณดํต์ ๊ฒฝ์ฐ ์ค์ ์ด ๊ผฌ์ฌ์ ๋ฎ์ด์์์ง๊ฒ ๋๋๋ฐ ์ด๋ ๋ฒ๊ทธ๋ผ๊ณ ํ๊ธฐ์ ์ ๋งคํ ์ํฉ์ด๋ผ ์ ๋ง ์ก๊ธฐ ์ด๋ ค์ด ์ฅ์ ๋ฅผ ๋ง๋ค์ด ๋ผ ์ ์๋ค. (๊ทธ๋์ ์ต๊ทผ ์คํ๋ง ๋ถํธ CoreApplication์์๋ ์๋ vs ์๋ ์ถฉ๋์ด๋๋ฉด ์ค๋ฅ๊ฐ ๋๋๋ก ๊ธฐ๋ณธ๊ฐ์ ๋ฐ๊พธ์๋ค.)
Overriding bean definition for bean 'memoryMemberRepository' with a different definition: replacing
# ์์กด๊ด๊ณ ์๋์ฃผ์ (@Autowired)
์์กด๊ด๊ณ๋ฅผ ์ฃผ์ ํ๋ ๋ฐฉ๋ฒ์ ์ด 4๊ฐ์ง๊ฐ ์๋ค.
- ์์ฑ์ ์ฃผ์
- ์์ ์ ์ฃผ์ (์์ฑ์ ๋์ setter์ฌ์ฉ)
- ํ๋ ์ฃผ์
- ์ผ๋ฐ ๋ฉ์๋ ์ฃผ์
@ ์์ฑ์ ์ฃผ์
ํน๋ณํ ์ด์ ๊ฐ ์๋ค๋ฉด, ์์ฑ์๋ก ์ฃผ์ ํ๋ ๊ฒ์ด ์ข๋ค.
์์์ ๊ณ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค. ์์ฑ์๋ฅผ ์ฌ์ฉํ๋ฉด ์ข์์ ์ด ํธ์ถ ์์ ์ ๋ฑ 1๋ฒ๋ง ํธ์ถ๋์ด ๋ถ๋ณํ ๊ฐ์ฒด ์์กด๊ด๊ณ๋ฅผ ๋ง๋ค ์๋ ์๋ค. ๋ ํ๋์ final ํค์๋๋ฅผ ์ ์ด ํน์๋ ์ด๊ธฐํ(์ค์ )๋์ง ์๋ ์ค๋ฅ๋ฅผ ์ปดํ์ผ ์์ ์ ์ก์ ์ ์๋ค.
* ์์ฑ์๊ฐ ๋ฑ 1๊ฐ๋ง ์๋ค๋ฉด, @Autowired๋ฅผ ์๋ตํด๋ ๋์ผํ๊ฒ ๋์ํ๋ค. (๋ฌผ๋ก ์คํ๋ง ๋น์๋ง ํด๋น๋๋ ๋ด์ฉ์ด๋ค.)
* ๋ง์ฝ ์๋์ผ๋ก ์ฃผ์ ํ ์คํ๋ง ๋น์ด ๋ฑ๋ก๋์ง ์์๋ค๋ฉด ์ค๋ฅ๋ฅผ ๋ฐ์์ํจ๋ค -> @Autowired(required=true) ์ต์
@Component public class OrderServiceImpl implements OrderService { private final MemberRepository memberRepository; private final DiscountPolicy discountPolicy; // ์์ฑ์๋ฅผ ํตํด์ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์
ํ๋ค. // Autowired ํค์๋๋ ํ์ฌ ๋ฑ๋ก๋ ๋น๋ค์ ํ์
์ ๋น๊ตํด์, ํ์ํ ๊ตฌํ์ฒด๋ฅผ ์ฐ๊ฒฐ์ํจ๋ค. @Autowired public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) { this.memberRepository = memberRepository; this.discountPolicy = discountPolicy; } }
@ ์์ ์ ์ฃผ์ (Setter)
๊ตฌํ์ฒด๊ฐ [์ ํ, ๋ณ๊ฒฝ] ๊ฐ๋ฅ์ฑ์ด ์๋ ๊ฒฝ์ฐ ์์ฑ์ ๋์ ์์ ์(Setter)๋ฅผ ์ฌ์ฉํ์ฌ ์ฃผ์ ํ๋ค. ๋ค๋ง ํน๋ณํ ๊ฒฝ์ฐ๊ฐ ์๋๋ผ๋ฉด ๊ตฌํ์ฒด์ ๋ถ๋ณ์ฑ์ ์งํค๊ธฐ ์ํด ์์ฑ์๋ก ์ฃผ์ ํ๋ ๊ฒ์ ๊ถ์ฅํ๋ค.
@Component public class OrderServiceImpl implements OrderService { private MemberRepository memberRepository; private DiscountPolicy discountPolicy; @Autowired public void setMemberRepository(MemberRepository memberRepository) { this.memberRepository = memberRepository; } @Autowired public void setDiscountPolicy(DiscountPolicy discountPolicy) { this.discountPolicy = discountPolicy; } }
@ ํ๋ ์ฃผ์ ( @Autowired Object a; )
์ด๋ฆ ๊ทธ๋๋ก ํ๋์ ๋ฐ๋ก ์ฃผ์ ํ๋ ๋ฐฉ๋ฒ์ธ๋ฐ, ์ค์ ์ฑ์์๋ ์ฌ์ฉํ์ง ์๋ ๊ฒ์ ์ถ์ฒํ๋ค. ์ฝ๋๋ ์งง์์ง์ง๋ง, ์ธ๋ถ์์ ๋ณ๊ฒฝ์ด ๋ถ๊ฐ๋ฅํด์ ๋์ค์ ํ ์คํธํ๊ธฐ ์ด๋ ต๋ค. ํ๋ ์ฃผ์ ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ์ค์ ์ฝ๋์ ์๊ด์๋ ํ ์คํธ ์ฝ๋๋ฅผ ๊ฐ๋จํ ์์ฑํ ๋, ํน์ ์คํ๋ง ์ค์ ์ ๋ชฉ์ ์ผ๋ก ํ๋ @Configuration ๊ฐ์ ํน๋ณํ ์ฉ๋๋ก๋ง ์ฌ์ฉ๋๋ค.
@Component public class OrderServiceImpl implements OrderService { @Autowired private MemberRepository memberRepository; @Autowired private DiscountPolicy discountPolicy; }
// ํ
์คํธ ์ฝ๋๋ฅผ ์์ฑํ ๋ ๋ง์ด ์ฌ์ฉํ๋ค. ๋ง ๊ทธ๋๋ก ํ
์คํธ์ฉ ์ฝ๋๋๊น @SpringBootTest class CoreApplicationTests { @Autowired OrderService orderService; @Test void contextLoads() { ... } }
@ ์ผ๋ฐ ๋ฉ์๋ ์ฃผ์
์์ฑ์, setter, ํ๋ ์ด์ธ์๋ ์๋ฌด ๋ฉ์๋์๋ Autowried๋ฅผ ์ฌ์ฉํด์ ์๋์ผ๋ก ์์กด๊ด๊ณ ์ฃผ์ ์ ๋ฐ์ ์ ์๊ธดํ๋ค. ํ์ง๋ง ๋ณดํต ์ฌ์ฉํ ์ผ์ด ์๋ ๊ธฐ๋ฅ์ด๋ค.
@Autowired public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy){ this.memberRepository=memberRepository; this.discountPolicy=discountPolicy; }
* ํ๋ฒ ๋ ๋งํ์ง๋ง, ์์กด๊ด๊ณ ์ฃผ์ ์ด๋ผํจ์ ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋ก๋์ด์๋ @Bean๋ค์ ์์กด๊ด๊ณ๋ฅผ ๋งํ๋ ๊ฒ์ด๋ค. ์คํ๋ง ๋น ๊ฐ์ฒด๋ก ๋ฑ๋ก๋์ง ์์ ์๋ฐ ํด๋์ค(Member)์ @Autowired ์ฝ๋๋ฅผ ์ ์ด๋ด์ผ ์๋์ผ๋ก ์ฃผ์ ๋์ง ์๋๋ค.
# ์ต์ ์ฒ๋ฆฌ, ์คํ๋ง ๋น์ด ์์ด๋ ๋์ํด์ผ ํ ๋
์๋์ผ๋ก ์ฃผ์ ํ ์คํ๋ง ๋น์ด ๋ฑ๋ก๋์ง ์์๋ค๋ฉด ์ค๋ฅ๋ฅผ ๋ฐ์์ํจ๋ค -> @Autowired(required=true) ์ต์
์คํ๋ง ์ปจํ ์ด๋์ ์๋ ์ฃผ์ ํ ๋น์ด ์์ ๋, ์ต์ ์ผ๋ก ๋ค๋ฅด๊ฒ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์๋์ ๊ฐ๋ค. ์ฐธ๊ณ ๋ก @Nullable๊ณผ Optional์ Autowired์ ์ฌ์ฉํ ๋ ๋ฟ ์๋๋ผ ํน์ ํ๋์๋ง ๋ฐ๋ก ์ฌ์ฉํ ์๋ ์๋ค.
- @Autowired(required=false) : ์๋ ์ฃผ์ ํ ๋์์ด ์์ผ๋ฉด ํด๋น ๊ฐ์ฒด์ ๋ฉ์๋ ํธ์ถ์ด ์๋๋๋ก ๋ง์.
- org.springframework.lang.@Nullable : ์๋ ์ฃผ์ ํ ๋์์ด ์์ผ๋ฉด null์ด ์ ๋ ฅ๋๋ค.
- Optional<> : ์๋ ์ฃผ์ ํ ๋์์ด ์์ผ๋ฉด Optional.empty ๊ฐ ์ ๋ ฅ๋๋ค
// Member๋ผ๋ ์คํ๋ง ๋น ์คํ๋ง ์ปจํ
์ด๋์ ์๋ค = ์๋ ์์กด์ฃผ์
์ด ๋ถ๊ฐ๋ฅํ๋ค. //ํธ์ถ ์๋จ, ์คํ์กฐ์ฐจ ๋์ง ์๊ณ ๋ฌด์๋จ (Member๋ ์คํ๋ง๋น์ด ์๋ ๊ทธ๋ฅ ์๋ฐ๊ฐ์ฒด์ด๋ฏ๋ก) @Autowired(required = false) public void setNoBean1(Member member){ System.out.println("setNoBean1 = "+member); } //null ํธ์ถ @Autowired public void setNoBean2(@Nullable Member member){ System.out.println("setNoBean2 = "+member); } //Optional.empty ํธ์ถ @Autowired(required = false) public void setNoBean3(Optional<Member> member){ System.out.println("setNoBean3 = "+member); }
// setNoBean1()์ ํธ์ถ์์ฒด๊ฐ ์๋จ. setNoBean2 = null setNoBean3 = Optional.empty
# final ํค์๋์ ์ฌ์ฉ
์์ฑ์ ์ฃผ์ ์ ์ฌ์ฉํ๋ฉด ํ๋์ final ํค์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ์ด๋ฅผ ์ด์ฉํ๋ฉด ์์ฑ์์์ ํน์๋ผ๋ ๊ฐ์ด ์ด๊ธฐํ(์ค์ )๋์ง ์๋ ์ค๋ฅ๋ฅผ ์ปดํ์ผ ์์ ์ ๋ง์์ค ์ ์๊ฒ ๋๋ค.
@Component public class OrderServiceImpl implements OrderService { private final MemberRepository memberRepository; private final DiscountPolicy discountPolicy; @Autowired public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) { this.memberRepository = memberRepository; } //... }
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev