#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;
}
//...
}
'๐ฑ Spring Framework > Spring Core' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
#10 ๋น ์๋ช ์ฃผ๊ธฐ ์ฝ๋ฐฑ (0) | 2021.08.03 |
---|---|
#9 ์์กด๊ด๊ณ ์๋์ฃผ์ ์์ ์๊ธฐ๋ ๋ฌธ์ (+Lombok ์๊ฐ) (0) | 2021.08.03 |
#7. ์คํ๋ง์ ์ฑ๊ธํค ์ปจํ ์ด๋ (@Configuration) (0) | 2021.08.02 |
BeanFactory, BeanDefinition (+ ์คํ๋ง ์ปจํ ์ด๋ XML ์ค์ ) (0) | 2021.08.02 |
#6. ์คํ๋ง ์ปจํ ์ด๋์ ์คํ๋ง ๋น (0) | 2021.08.02 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev