DevLog ๐ถ
[Spring] ์ปดํฌ๋ํธ ์ค์บ๊ณผ ์์กด๊ด๊ณ ์๋ ์ฃผ์ ๋ณธ๋ฌธ
[Spring] ์ปดํฌ๋ํธ ์ค์บ๊ณผ ์์กด๊ด๊ณ ์๋ ์ฃผ์
dolmeng2 2022. 8. 7. 16:18- ๊น์ํ ๋์ '์คํ๋ง ํต์ฌ์๋ฆฌ - ๊ธฐ๋ณธํธ'์ ๋ณด๊ณ ์ ๋ฆฌํ ๊ธ์ ๋๋ค ๐
- ์ง๋ ํฌ์คํ ๊ณผ ์ด์ด์ง๋๋ค :D
| ์ปดํฌ๋ํธ ์ค์บ
- ์ง๋ ํฌ์คํ ๊น์ง ์ฐ๋ฆฌ๋ AppConfig๋ผ๋ ์ค์ ์ ๋ณด ํด๋์ค๋ฅผ ์ด์ฉํด ์คํ๋ง ๋น์ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์ ํ์๋ค.
- ๊ทธ๋ฌ๋, ๋น์ ๊ฐ์๊ฐ ๋ง์์ง์๋ก ์ด๋ฅผ ํ๋์ฉ ๊ด๋ฆฌํ๋ ๊ฑด ๋๋ฌด ๊ท์ฐฎ์ ์ผ์ด๋ค.
- ์ค์ ์ ๋ณด๊ฐ ์์ด๋ ์๋์ผ๋ก ์คํ๋ง ๋น์ ๋ฑ๋กํ ์ ์์๊น? ์์กด๊ด๊ณ๋ ์์์ ํด์คฌ์ผ๋ฉด ์ข๊ฒ ์ด.
- ๐ฉ์ปดํฌ๋ํธ ์ค์บ, ๊ทธ๋ฆฌ๊ณ @Autowired๋ฅผ ์ฌ์ฉํด๋ณด์!
[AutoAppconfig.java]
@Configuration
@ComponentScan(excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION, classes = Configuration.class))
public class AutoAppConfig {
}
- @Bean์ด ํ๋๋ ์๋ ๊ฒ์ ๋ณผ ์ ์๋ค!
- @Component๊ฐ ๋ถ์ ํด๋์ค๋ฅผ ์ค์บํ์ฌ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๊ฒ ๋๋ค.
- ์ด๋, ๊ธฐ์กด์ ์์ ์ฝ๋์ธ AppConfig.java ์ญ์ @Configuration์ด ๋ถ์ด ์์ด ์ค์บ ๋์์ด ๋๊ธฐ ๋๋ฌธ์, ๋ฑ๋ก๋์ง ์๊ฒ ํ๊ธฐ ์ํด์ excludeFilters๋ฅผ ์ฌ์ฉํ์๋ค. (์๋๋ @Configuration์ด ๋ถ์ ํด๋์ค๋ ๊ฐ์ด ์ค์บํด์ฃผ๋ ๊ฒ ๋ง๋ค)
- ์ฐธ๊ณ ๋ก, @Configuration ๋ด๋ถ์ @Component๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ปดํฌ๋ํธ ์ค์บ์ ๋์์ด ๋๋ ๊ฒ์ด๋ค!
- โญ ์ดํ์ ๋์ฌ ๋ค์ํ ์ด๋ ธํ ์ด์ (@Service, @Repository... ๋ฑ๋ฑ์๋ @Component๊ฐ ๋ถ์ด ์๋ค!)
- โญ ์ฐธ๊ณ ๋ก! AutoAppConfig์ ์์น๊ฐ ๋งค์ฐ ์ค์ํ๋ค.
- ์ดํ ๋์ค๊ฒ ์ง๋ง, ์ปดํฌ๋ํธ ์ค์บ ์ ๋์ ๋ฐ ํ์ ํจํค์ง๋ฅผ ์ค์บํ๊ธฐ ๋๋ฌธ์, ๋ณธ ์์ ์์๋ ~Application.java๊ฐ ์กด์ฌํ๋ ํ์ผ์ ๊ฒฝ๋ก์ ๋์ผํ ์์น์ ๋์๋ค. (src > main > java > group_name > directory_name > ์ฌ๊ธฐ!)
โ ๊ธฐ์กด ์ฝ๋ ์์
- MemoryMemberRepository, RateDiscountPolicy์ @Component๋ฅผ ์ถ๊ฐํด์ค๋ค.
[MemberServiceImpl.java]
@Component
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
@Autowired
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
- ์ฌ๊ธฐ์๋ ์์กด๊ด๊ณ ์ฃผ์ ์ ์ํด์ @Autowired๋ฅผ ์ถ๊ฐ์ ์ผ๋ก ๋ถ์ฌ์ฃผ์๋ค.
- OrderServiceImpl์์๋ ๋์ผํ ๋ฐฉ์์ผ๋ก ์ถ๊ฐ๋ฅผ ํด์ฃผ์.
โ Test
public class AutoAppConfigTest {
@Test
public void basicScan() throws Exception {
ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);
MemberService bean = ac.getBean(MemberService.class);
assertThat(bean).isInstanceOf(MemberService.class);
}
}
- ํ ์คํธ๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์คํ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
โ ๋์ ๊ณผ์
1. @ComponentScan์ @Component๊ฐ ๋ถ์ ๋ชจ๋ ํด๋์ค๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๋ค.
- ๊ธฐ๋ณธ์ ์ผ๋ก ํด๋์ค๋ช ์ ์คํ๋ง ๋น ์ด๋ฆ์ผ๋ก ์ฌ์ฉํ๋ค. @Component("name")์ผ๋ก ์ง์ ์ง์ ๋ ๊ฐ๋ฅํ๋ค.
- ์ด๋, ํด๋์ค๋ช ์ ๊ฐ์ฅ ์ฒซ ๊ธ์๋ ์๋ฌธ์๋ก ๋ฑ๋กํ๋ค.
2. ์์ฑ์์ ๊ธฐ์ ํ @Autowired๋ฅผ ํตํด, ์คํ๋ง ์ปจํ ์ด๋๋ ์๋์ผ๋ก ํด๋น ์คํ๋ง ๋น์ ์ฐพ์์ ์ฃผ์ ํ๋ค.
- ์ด๋, ํ์ ์ด ๊ฐ์ ๋น์ ์ฃผ์ ํ๋ค. = ac.getBean(MemberRepository.class)
โ ์ปดํฌ๋ํธ ์ค์บ ์์ ์์น
- @ComponentScan(basePackages = "")๋ก ์ง์ ์ด ๊ฐ๋ฅํ๋ค.
- ํด๋น ํจํค์ง๋ฅผ ํฌํจํ, ํ์ ํจํค์ง๋ฅผ ๋ชจ๋ ํ์ํ๋ค.
- {}๋ก ๋ฌถ์ด์ ๋ค์ค ์ง์ ๋ ๊ฐ๋ฅํ๋ค.
- ํน์ basePackageClasses ์ต์ ์ ํตํด์ ํด๋์ค์ ํจํค์ง๋ฅผ ์์ ์์น๋ก ๋ ์ ์๋ค.
- ๋ณดํต์ ํ๋ก์ ํธ ์ต์๋จ์ ๋๋ ๊ฒ ๊ธฐ๋ณธ์ด๋ค.
- ์ฐธ๊ณ ๋ก, @SpringBootApplication ๋ด๋ถ์๋ @ComponentScan์ด ๋ค์ด์๋ค.
| ์ปดํฌ๋ํธ ์ค์บ - ํํฐ
- ์ปดํฌ๋ํธ ์ค์บ ๋์์ ์ถ๊ฐ๋ก ์ง์ ํ๊ฑฐ๋, ์ ์ธํ ๋์์ ์ง์ ํด๋ณด์.
[MyIncludeComponent.java]
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
}
- ์ปดํฌ๋ํธ ์ค์บ ๋์์ ์ถ๊ฐํ ์ปค์คํ ์ ๋ ธํ ์ด์ ์ด๋ค.
- @Target์ ํด๋น ์ด๋ ธํ ์ด์ ์ ์ด๋์ ๋ถ์ผ์ง, @Retention์ ์ด๋ ธํ ์ด์ ์ ์๋ช ์ฃผ๊ธฐ, @Documented๋ javadoc์ ํตํ api ๋ฌธ์ ์์ฑ ์ ํด๋น ์ด๋ ธํ ์ด์ ์ ์ค๋ช ๋ ํฌํจํด์ฃผ๋ ์ญํ ์ ํ๋ค.
- ๋ณดํต์ @Target ์ ๋๋ง ์ปค์คํ ์ ํ๊ณ , ๋๋จธ์ง๋ ๋๋ถ๋ถ ๊ทธ๋๋ก ์ค์ ํ๋ค๊ณ ๋ด๋ ๋๋ค.
[MyExcludeComponent.java]
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}
- ๋ง์ฐฌ๊ฐ์ง๋ก ์ ๊ฑฐ ๋์์ ์ถ๊ฐํ ์ปค์คํ ์ ๋ ธํ ์ด์ ๋ ์์ฑํด์ฃผ์.
[BeanA.java, BeanB.java]
@Component
@MyIncludeComponent
public class BeanA {
}
@Component
@MyExcludeComponent
public class BeanB {
}
- ๊ทธ๋ฆฌ๊ณ , ํด๋น ์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ ํด๋์ค๋ค๋ ๊ฐ๊ฐ ์ ์ํด์ฃผ์. (@Component๋ ๋ถ์ฌ์ฃผ์)
โ Test
public class ComponentFilterTest {
@Test
public void filterScan() throws Exception {
ApplicationContext ac = new AnnotationConfigApplicationContext(ComponentFilterConfig.class);
BeanA beanA = ac.getBean("beanA", BeanA.class);
assertThat(beanA).isNotNull();
assertThrows(NoSuchBeanDefinitionException.class,
() -> ac.getBean("beanB", BeanB.class));
}
@Configuration
@ComponentScan(
includeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION, classes = MyIncludeComponent.class),
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION, classes = MyExcludeComponent.class)
)
static class ComponentFilterConfig {
}
}
ํ์ธํด๋ณด๋ฉด, includeFilter์ ์ ์ฉ๋ @MyIncludeComponent๋ฅผ ๊ฐ์ง beanA์ ๊ฒฝ์ฐ getBean์ผ๋ก ์ ์ฐพ์์ค์ง๋ง, excludeFilter์ ์ ์ฉ๋ @MyExcludeComponent๋ฅผ ๊ฐ์ง beanB์ ๊ฒฝ์ฐ ์์ธ๊ฐ ํฐ์ง๋ค.
์ฝ๊ฒ ์๊ฐํด์, includeFilters์ ์ ์ธ๋ class๋ @Component ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ์ค ๊ฒ๊ณผ ๋์ผํ ์ญํ ์ ํ๋ ๊ฒ!
๐ฑ ์ฌ๊ธฐ์, static class๋ก ComponentFilterConfig๋ฅผ ์ ์ธํ ์ด์
static์ผ๋ก ํ์ง ์์ผ๋ฉด inner class๋ outer class์ ์ข ์๋๊ธฐ ๋๋ฌธ์, outer class์ ๊ฐ์ฒด๊ฐ ์์ฑ๋์ด์ผ๋ง ์ ๊ทผ์ด ๊ฐ๋ฅํด์ง๋ค.
๋ฐ๋ฉด์, static์ผ๋ก ์ ์ธํ๋ฉด outer class์ ๊ฐ์ฒด ์์ฑ ์ ๋ฌด์ ์๊ด์์ด ๋ณ๊ฐ๋ก ๋ง๋ค์ด์ง๊ธฐ ๋๋ฌธ์ ComponentFilterConfig ํด๋์ค๊ฐ ์์ฑ๋๊ณ ๋น์ผ๋ก ๋ฑ๋ก๋ ์ ์๊ฒ ๋๋ค. (์ ์ธํ์ง ์์ผ๋ฉด ComponentFilterTest ํด๋์ค๊ฐ ๋จผ์ ๋ง๋ค์ด์ ธ์ผ ํ๋๋ฐ, ์ ๋ง๋ค์ด์ก์ผ๋ ๋น์ฐํ Bean์ ๋ชป ์ฐพ์์จ๋ค)
| ์ปดํฌ๋ํธ ์ค์บ - ๋์ผํ ๋น ์ด๋ฆ ๋ฑ๋ก
- ์๋ ๋น ๋ฑ๋ก์ผ๋ก ๋ฑ๋ก๋ 2๊ฐ์ ๋น์ด ๋์ผํ ์ด๋ฆ์ ๊ฐ์ง๋ค๋ฉด?
- ConflictingBeanDefinitionException ์์ธ ๋ฐ์
- ์๋ ๋น ๋ฑ๋ก์ผ๋ก ๋ฑ๋กํ ๋น๊ณผ ์๋ ๋น ๋ฑ๋ก์ผ๋ก ๋ฑ๋กํ ๋น์ด ๋์ผํ ์ด๋ฆ์ ๊ฐ์ง๋ค๋ฉด?
- ์ด๋๋ ์๋ ๋น ๋ฑ๋ก์ด ์ฐ์ ์ด ๋์ด, ์๋ ๋น์ด ์๋ ๋น์ ์ค๋ฒ๋ผ์ด๋ฉํด๋ฒ๋ฆฐ๋ค.
- ๊ทผ๋ฐ ์ต๊ทผ์๋ ๋์ด ์ถฉ๋๋๋ฉด ์ค๋ฅ๋๋๋ก ๋ฐ๊พธ์๋ค๊ณ ํ๋ค!
| ์์กด๊ด๊ณ ์ฃผ์ ๋ฐฉ๋ฒ
- ํฌ๊ฒ 4๊ฐ์ง๋ก ๋๋ ์ ์๋ค. (์์ฑ์, ์์ ์, ํ๋, ๋ฉ์๋)
โ ์์ฑ์ ์ฃผ์
@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;
}
}
- ์์ฑ์๋ฅผ ํตํด์ ์ฃผ์ ๋ฐ๋ ๋ฐฉ๋ฒ. (๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋๋ค)
- ์์ฑ์ ํธ์ถ ์์ ์ 1๋ฒ๋ง ํธ์ถ๋๋ ๊ฒ์ด ๋ณด์ฅ๋๋ค.
- ๋ถ๋ณํ๋ฉฐ, ํ์์ ์ธ ์์กด๊ด๊ณ์ ์ฌ์ฉํ๋ค.
- ๊ฐ ํ๋๋ฅผ final๋ก ์ค์ ํ์๋๋ฐ, ์ด๋ ๊ฐ์ด ๊ผญ ์ธํ ๋์ด์ผ ํจ์ ๋ณด์ฅํ ๋ ์ฌ์ฉํ๋ค. (์์ฑ์ ๋นผ๋ฉด ์ค๋ฅ๋๋ค)
โญ ์คํ๋ง ๋น์ ์์ฑ์๊ฐ 1๊ฐ ์์ผ๋ฉด @Autowired๋ฅผ ์๋ตํด๋ ์๋ ์ฃผ์ ๋๋ค!
- ๋ณดํต @RequiredArgConstructor์ ํจ๊ป ์ ์ฉํ๊ฒ ์ฐ์ธ๋ค.
- ์์ฑ์ ์ฃผ์ ์ ๊ฒฝ์ฐ, OrderServiceImpl์ ์์ฑํ๋ ์์ ์ ์์ฑ์๋ฅผ ํธ์ถํ๋ฉฐ ๋น ๋ฑ๋ก + ์์กด๊ด๊ณ ์ฃผ์ ๋ ํจ๊ป ์ผ์ด๋๋ค.
โ ์์ ์ ์ฃผ์ (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;
}
}
- setter๋ฅผ ํตํด ํ๋์ ๊ฐ์ ๋ณ๊ฒฝํ์ฌ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์ ํ๋ค. (์์ ํด์ผ ํ๋๊น final ์ ๊ฑฐ)
- ์ ํ์ , ๋ณ๊ฒฝ ๊ฐ๋ฅ์ฑ์ด ์๋ ์์กด๊ด๊ณ์ ์ฌ์ฉํ๋ค.
- ์ ํ์ ์ด๋ผ๋ ๊ฒ์ @Autowired(required=false)๋ก ๋์ด์ ์ฃผ์ ํ ๋์์ด ์์ด๋ ๋์ํ๋๋ก ํ ์ ์๋ค๋ ์๋ฏธ์ด๋ค.
- ํด๋น ์ต์ ์ ์ฌ์ฉํ๋ฉด, ์๋ ์ฃผ์ ํ ๋์์ด ์์ ๋ ์์ ์ ์์ฒด๊ฐ ํธ์ถ๋์ง ์๋๋ค.
- ํน์, ํ๋ผ๋ฏธํฐ์ @Nullable์ ๋ถ์ด๊ฑฐ๋ Optional<>๋ก ๊ฐ์ธ์ฃผ๋ ๋ฐฉ๋ฒ๋ ์๋ค. ์ด ๊ฒฝ์ฐ null, Optional.empty๋ก ๋ค์ด๊ฐ๋ค.
- ์์ฑ์ ์ฃผ์ ๊ณผ ๋ฌ๋ฆฌ, ๊ฐ์ฒด ์์ฑ ์์ ์ด ์๋ ๊ทธ ์์ฑ ์ดํ ์์กด๊ด๊ณ๊ฐ ์ฃผ์ ๋๋ค.
โ ํ๋ ์ฃผ์
@Component
public class OrderServiceImpl implements OrderService {
@Autowired
private MemberRepository memberRepository;
@Autowired
private DiscountPolicy discountPolicy;
}
- ํ๋์ ๊ทธ๋๋ก ์ฃผ์ ํ๋ ๋ฐฉ๋ฒ์ด๋ค. ๋จ์ํ @Autowired๋ง ๋ถ์ฌ์ฃผ๋ฉด ๋๋ค.
- ์ธ๋ถ์์ ๋ณ๊ฒฝ์ด ๋ถ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ํ ์คํธ๊ฐ ์ด๋ ค์ฐ๋ฉฐ, DI ํ๋ ์์ํฌ๊ฐ ๊ผญ ํ์ํ๋ค. ๋ฌด์กฐ๊ฑด ์คํ๋ง์์ ๊ฐ์ ธ์์ผ ํ๋ค.
- ์ฌ๋งํ๋ฉด ์ฌ์ฉํ์ง ๋ง๊ณ , @Configuration ๊ฐ์ ๊ณณ์์๋ง ํน์์ ์ผ๋ก ์ฌ์ฉํ ๊ฒ. (ํน์ ํ ์คํธ ์ฝ๋์์)
โ ์ผ๋ฐ ๋ฉ์๋ ์ฃผ์
@Component
public class OrderServiceImpl implements OrderService {
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void init(MemberRepository memberRepository, DiscountPolicy
discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
- ํ ๋ฒ์ ์ฌ๋ฌ ํ๋๋ฅผ ์ฃผ์ ๋ฐ์ ์ ์๋ค.
- ์ผ๋ฐ์ ์ผ๋ก๋ ๊ฑฐ์ ์ฌ์ฉํ์ง ์๋๋ค.
๐ฉ ์ ๋ง ๋น์ฐํ ์๋ฆฌ์ง๋ง, ์์กด๊ด๊ณ ์๋ ์ฃผ์ ์ ์คํ๋ง ์ปจํ ์ด๋์์ ๊ด๋ฆฌํ๋ ์คํ๋ง ๋น์ด์ด์ผ ํ๋ค.
์ผ๋ฐ ํด๋์ค์ @Autowired๋ฅผ ์ ์ฉํด๋ ๋น์ฐํ ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์๋๋ค!
| ๋ฌด์จ ์ฃผ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํด์ผ ํ ๊น?
- ์์ฑ์ ์ฃผ์ ๋ฐฉ๋ฒ์ ๊ถ์ฅํ๋ค. (๋ด๊ฐ ์๊ธฐ๋ก๋ ์คํ๋ง์์๋ ๊ธฐ๋ณธ์ผ๋ก ๊ถ์ฅํ๋ ๋ฐฉ๋ฒ์ผ๋ก ์๊ณ ์๋ค.)
โ ๋ถ๋ณ์ฑ
์์กด๊ด๊ณ๊ฐ ์ฃผ์ ๋ ์ด์, ์ข ๋ฃ ์์ ๊น์ง ๋ณ๊ฒฝํ ์ผ์ ๊ฑฐ์ ์กด์ฌํ์ง ์๋๋ค.
์คํ๋ ค, ์์ ์ ์ฃผ์ ์ฒ๋ผ ์ด์ด๋๊ฒ ๋๋ฉด ๋ณ๊ฒฝ์ด ๋ฐ์๋ ์ ์๊ธฐ ๋๋ฌธ์ ์๋นํ ์ํํ๋ค.
์์ฑ์ ์ฃผ์ ์ ๊ฐ์ฒด์ ์์ฑ ์์ ์ ๋ฑ 1๋ฒ๋ง ํธ์ถ๋๊ธฐ ๋๋ฌธ์, ์ดํ์ ๋ณ๊ฒฝ๋๋ ์ผ์ด ์๋ค.
โ ํ์์ฑ
์์ ์ ์ฃผ์ ์ ๊ฒฝ์ฐ, ์คํ๋ง ์ฌ์ฉ ์์ด ๋จ์ํ ์๋ฐ ์ฝ๋๋ง์ผ๋ก ํ ์คํธ๋ฅผ ์งํํ ๋
-> ์๋ฐ ์ฝ๋๋ง์ผ๋ก ํ ์คํธ = ์คํ๋ง ์ปจํ ์ด๋๋ฅผ ๊ฑฐ์น์ง ์๊ณ (ac.getBean) new๋ฅผ ํตํด ๊ฐ์ฒด๋ฅผ ์์ฑํด์ ์งํํ๋ ํ ์คํธ.
@Autowired๋ฅผ ๋ถ์ด๋ฉด ์์กด๊ด๊ณ๊ฐ ์์ด๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง ์๋๋ค. (์ปดํ์ผ ์์ ์ค๋ฅ x)
๊ทธ๋ฌ๋, ๋ง์ ์คํํ๊ณ ๋๋ฉด NPE๊ฐ ๋จ๋๋ฐ, ๋น์ฐํ ์์กด๊ด๊ณ๊ฐ ์์ผ๋ ์คํ ์์ ์ ์ค๋ฅ๊ฐ ๋๋ค.
๋ฐ๋ฉด์, ์์ฑ์ ์ฃผ์ ์ ๊ฒฝ์ฐ ์ฃผ์ ํ์ง ์์์ ๋ ์ปดํ์ผ ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ํ์ธํ๊ธฐ ์ข๋ค.
๋, ์์กด๊ด๊ณ๋ฅผ ๋ณดํต ํ๋ผ๋ฏธํฐ๋ก ๋ฃ์ด์ฃผ๊ธฐ ๋๋ฌธ์ ์ฝ๋๋ฅผ ๊น๋ณด์ง ์์๋ ๋ญ๊ฐ ๋ค์ด๊ฐ๋์ง ํ์ธํ๊ธฐ ์ข๋ค ใ ใ
โ final ํค์๋
์์ฑ์ ์ฃผ์ ์ ๊ฒฝ์ฐ, ๊ฐ์ฒด ์์ฑ ์์ ์ ํธ์ถ๋๊ณ ํ๋ผ๋ฏธํฐ๊ฐ ์ด๊ธฐํ๋๊ธฐ ๋๋ฌธ์ final ํค์๋๊ฐ ์ฌ์ฉ ๊ฐ๋ฅํ์ง๋ง,
์์ ์ ์ฃผ์ ์ ๊ฒฝ์ฐ ๊ฐ์ฒด ์์ฑ ์ดํ ํธ์ถ ๋ฐ ์ด๊ธฐํ๊ฐ ๋๊ธฐ ๋๋ฌธ์ final ํค์๋ ์ฌ์ฉ์ด ๋ถ๊ฐ๋ฅํ๋ค.
๐ฉ final ํค์๋๋ ์์ํ์ํค๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์, ์ฌ์ ์, ์์ ๋ฑ์ด ๋ถ๊ฐ๋ฅํด์ง๋ค. ์ฌ์ ์๊ฐ ์ ๋๊ธฐ ๋๋ฌธ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ์ธ๊ณผ ๋์์ ๊ฐ์ ํ ๋นํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ด๋ค. ํ์ง๋ง, ์์ฑ์๋ฅผ ํตํด์ ์์๋ฅผ ์ด๊ธฐํํ๊ฒ ๋๋ฉด ์ ์ธ๊ณผ ๋์์ ํ ๋น์ ํ์ง ์์๋ ๋๋๋ฐ, ์ด๋ '์์ฑ์'๋ผ๋ ์ ์ ์์ฒด๊ฐ ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ๋ฌด์กฐ๊ฑด ์งํํ๋ ๊ณผ์ ์ค ํ๋์ด๊ณ , ์์๊ฐ์ ์ด๊ธฐํํ๋ค๋ฉด ํด๋น ์์๋ '๋ฐ๋์ ๊ฐ์ ํ ๋น๋ฐ์'์ ๋ณด์ฅํ๊ธฐ ๋๋ฌธ์ ์ปดํ์ผ ์ค๋ฅ๊ฐ ๋์ง ์๋๋ค.
๐ฉ ๊ทธ๋ฌ๋, setter์ ๊ฒฝ์ฐ ๊ฐ์ฒด๊ฐ ์์ฑ๋ ์ดํ์! .set()์ ์ด์ฉํด์ ์ ๊ทผํ๊ธฐ ๋๋ฌธ์ ๋ณ์์ ๊ฐ์ ํ ๋นํ๊ฒ ๋๋ค. ์ด๋, ํด๋น ๊ฐ์ฒด์ ์์๊ฐ ์กด์ฌํ๊ฒ ๋๋ฉด ์์๋ ์์ฑ์ด ๋์์ง๋ง ์ปดํ์ผ๋ฌ ์์ ์์๋ ์ธ์ ์ด๊ธฐํ๋ ์ง ์ ์ ์๊ธฐ ๋๋ฌธ์ ๋ณดํต final ํค์๋ ์ฌ์ฉ์ ๋ง์๋๋๋ค.
์๋ฌดํผ, final์ ์ฌ์ฉํ๊ฒ ๋๋ฉด ์์ ํ๋๊ฐ ์์ ๋ ๊ฐ๋ฐ์๊ฐ this.a = a; ์ด๋ฐ ์์ผ๋ก ํ๋์ ๊ฐ์ ์ฃผ์ ํ์ง ์์ ๋ ์ปดํ์ผ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค! ๋ชจ๋ ์ค๋ฅ ์ค์์ ์ปดํ์ผ ์์ ์ค๋ฅ๊ฐ ๊ฐ์ฅ ์ข๋ค. ํด๊ฒฐํ๊ธฐ๋ ์ข๊ณ ...
์ถ๊ฐ์ ์ผ๋ก, ํ๋ ์ฃผ์ ์ ๊ฒฝ์ฐ ์ฌ์ฉํ์ง ์๋ ๊ฒ ์ข๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ํ๋ ์ฃผ์ ์ ์คํ๋ง ์ปจํ ์ด๋๋ฅผ ๊ผญ ๊ฑฐ์น๊ธฐ ๋๋ฌธ์ ํ ์คํธ ๋จ๊ณ์์ ๊ฐ๋ฐ์๊ฐ ์์๋ก ์ฃผ์ ํ๋ ๊ฒ ์์ฒด๊ฐ ๋ถ๊ฐ๋ฅํด์ง๋ค.
| ๋ ์งง๊ฒ ์ต์ ํํด๋ณด์!
- ์์ฑ์ ์ฃผ์ ์ ์ฌ์ฉํ๋ ๊ฑด ์ข์ง๋ง, ์๋ฌด๋๋ ์์ฑ์๊ฐ ๊ผญ ์์ด์ผ ํ๋ค๋ ์ ์ด ์ฝ๋๊ฐ ๋ณต์กํด์ง๋ค๊ณ ์๊ฐํ ์ ์์ ๊ฒ์ด๋ค.
- ํ์ง๋ง...! ์ค์ ๋ก ๊ฐ๋ฐํ ๋๋ ์์ฑ์๋ฅผ ์จ์ค ํ์๊ฐ ์๋ค. Lombok์ ์ฌ์ฉํ๋ฉด ๋๊ธฐ ๋๋ฌธ์!
[OrderServiceImpl.java]
@Component
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
// @Autowired //์์ฑ์๊ฐ 1๊ฐ๋ผ๋ฉด @Autowired ์๋ต ๊ฐ๋ฅ
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
- ๊ธฐ์กด์ ์ฝ๋์ด๋ค. @Autowired๋ ์๋ตํ ์ ์์ง๋ง, ์ฌ์ ํ ์์ฑ์๊ฐ ์กด์ฌํ๋ ๊ฒ ๋ชป๋ง๋ ํ๋ค.
- Lombok์ ์ ์ฉํด๋ณด์!
[build.gradle] - dependency ์ถ๊ฐ
- ์ฌ๋งํ๋ฉด SpringBoot๋ก ํ๋ก์ ํธ ์์ฑ ์ lombok์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฒดํฌํ๋ ๊ฒ ์ข๋ค. ์ ์ฉํ ๊ฒ ๋งค์ฐ ๋ง๊ธฐ ๋๋ฌธ์...!
plugins {
id 'org.springframework.boot' version '2.7.2'
id 'io.spring.dependency-management' version '1.0.12.RELEASE'
id 'java'
}
group = 'study'
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'
}
tasks.named('test') {
useJUnitPlatform()
}
- ์ถ๊ฐํ๊ณ ๋์ ์ฝ๋ผ๋ฆฌ ๋ชจ์ ํด๋ฆญ or ์ค๋ฅธ์ชฝ์ Gradle -> Reload ํด๋ฆญํด์ ์ ์ฉ์ ํด์ค์ผ ํ๋ค.
- ์ดํ, ์ค์ ์์ Annotation processors -> Enable annotation processing์ ํด์ฃผ์.
๊ทธ๋ฆฌ๊ณ , ์ฝ๋๋ฅผ ์ด๋ ๊ฒ ์์ ํด๋ณด์.
[OrderServiceImpl.java]
@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
}
- ์ฝ๋๊ฐ ๋งค์ฐ ๊ฐ๊ฒฐํด์ก๋ค. ๋๋ถ๋ถ ๊ฐ๋ฐํ ๋ ์ด๋ ๊ฒ ์ฌ์ฉํ๋๊น ๊ผญ ๊ธฐ์ตํด๋๋๋ก ํ์.
- ๋กฌ๋ณต์ ์ฌ์ฉํ๋ฉด ํ๋๋ช ์ ๊ธฐ์ค์ผ๋ก ์์ฑ์ ๋งค๊ฐ๋ณ์ ์ด๋ฆ์ ๊ฐ์ง๊ธฐ ๋๋ฌธ์, ๊ฐ ํ๋๋ช ์ผ๋ก ๋น์ด ๋ฑ๋ก๋๋ค.
| ๋์ผํ ํ์ ์ ๊ฐ์ง ๋น
- @Autowired๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ ์ผ๋ก ์กฐํํ๋ค.
- ์ด์ ์ ์์ ์์, ์ ์ก ํ ์ธ ์ ์ฑ (Fix)๊ณผ ์ ๋ฅ ํ ์ธ ์ ์ฑ (Rate)์ ๋ชจ๋ DiscountPolicy ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ๊ตฌํ์ฒด์ด๋ค.
- ๋ง์ฝ, ๋์ @Component๋ฅผ ํตํด ๋น์ผ๋ก ๋ฑ๋กํ๊ณ , DiscountPolicy์ @Autowired๋ฅผ ๋ถ์ด๋ฉด ์ด๋ค ๊ฒ ์ฃผ์ ๋ ๊น?
์ด ๊ฒฝ์ฐ, NoUniqueBeanDefinitionException ์์ธ๊ฐ ๋ฐ์ํ๋ค.
โ ํด๊ฒฐ ๋ฐฉ๋ฒ
- @Autowired ์ฌ์ฉ ์ ํ๋๋ช ์ ์ด์ฉ
@Autowired
private DiscountPolicy rateDiscountPolicy
๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ๊ฒ ๋๋ฉด, 1์ฐจ์ ์ผ๋ก DiscountPolicy ํ์ ๋งค์นญ -> rateDiscountPolicy ํ๋๋ช ๋งค์นญ์ ์งํํ๋ค.
(๋ฌผ๋ก , DiscountPolicy๊ฐ ์ค๋ณต๋์ง ์๋๋ค๋ฉด ํ๋๋ช ๋งค์นญ๊น์ง ๊ฐ์ง ์๋๋ค. 2๊ฐ ์ด์์ผ ๋๋ง ์งํ)
- @Qualifier ์ฌ์ฉํ๊ธฐ
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}
๋ค์๊ณผ ๊ฐ์ด, ๋น์ ๋ฑ๋กํ ๋ ์ถ๊ฐ์ ์ธ ๊ตฌ๋ถ์๋ฅผ ์ค์ ํ ์ ์๋ค. (@Bean์๋ ํจ๊ป ์ฌ์ฉํ ์ ์๋ค)
@Autowired
public OrderServiceImpl(MemberRepository memberRepository,
@Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
์ดํ, ์ฃผ์ ํ ๋ ๋ค์๊ณผ ๊ฐ์ด ๋ฑ๋กํ ๊ตฌ๋ถ์๋ฅผ ๋ฃ์ด์ฃผ๋ฉด ๋๋ค.
๋จ, ์ฃผ์ ํ ๋ @Qualifier๋ฅผ ๊ณ์ ๋ถ์ฌ์ค์ผ ํ๋ค๋ ์ ์ด ๋จ์ ์ด๋ค.
- @Primary ์ฌ์ฉํ๊ธฐ
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
@Primary๋ฅผ ๋ถ์ฌ์ฃผ๋ฉด ํด๋น ๋น์ด ์ฐ์ ๊ถ์ ๊ฐ์ง๊ฒ ๋๋ค.
์ฃผ์ ์ DiscountPolicy์ ๋ณ๋ค๋ฅธ ์ฒ๋ฆฌ๋ฅผ ํ์ง ์์๋ RateDiscountPolicy๊ฐ ๋ค์ด๊ฐ๋ค.
๐ฉ ์คํ๋ง์ ํญ์ ์๋๋ณด๋ค ์๋์ด, ๋์ ๊ฒ๋ณด๋ค ์ข์ ๋ฒ์๊ฐ ์ฐ์ ๊ถ์ ๊ฐ์ง๋ค.
@Qualifier๋ ๋ ์ธ์ธํ ์์ ์ ์ฃผ๋ก ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์, @Primary์ ๋นํด์ ์ฐ์ ์์๊ฐ ๋๋ค!
๐ฉ ์ฐธ๊ณ ๋ก, @RequriedArgsConstructor๋ฅผ ์ฌ์ฉํ๋ฉด ์ ๋ ธํ ์ด์ ์ ๋ณด๋ ํฌํจ์ํค์ง ์๊ณ ์์ฑ์๋ฅผ ๋ง๋ ๋ค.
์ฆ, @Qualifier๋ฅผ ๋ถ์ฌ๋ ํด๋น ๊ตฌ๋ถ์๊ฐ ์ ์ฉ๋์ง ์๋๋ค๋ ๊ฒ. ๊ตฌ๋ถ์๋ฅผ ์ง์ ํ๊ณ ์ถ๋ค๋ฉด ํ๋๋ช ์ ๋ฐ๊พธ์.
(์ ์ฉํ ์ ์๋ ๋ฐฉ๋ฒ์ ์๊ธฐ๋ ํ๋ฐ... config ์ ๋ณด๋ฅผ ์์ ํด์ผ ํ๋ ๊ฑฐ๋๊น ์ฌ๋งํ๋ฉด ํ๋ ์ด๋ฆ์ ๋ฐ๊พธ์!)
| ๋์ผํ ํ์ ์ ๊ฐ์ง ๋น - ๋ชจ๋ ์ฌ์ฉํ๊ธฐ
โ Test
public class AutoAppConfigTest {
@Test
public void findAllBean() throws Exception {
ApplicationContext ac
= new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);
DiscountService discountService = ac.getBean(DiscountService.class);
Member member = new Member(1L, "userA", Grade.VIP);
int discountPrice = discountService.discount(member, 10000, "fixDiscountPolicy");
assertThat(discountService).isInstanceOf(DiscountService.class);
assertThat(discountPrice).isEqualTo(1000);
}
static class DiscountService {
private final Map<String, DiscountPolicy> policyMap;
private final List<DiscountPolicy> policies;
public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) {
this.policyMap = policyMap;
this.policies = policies;
System.out.println("policyMap = " + policyMap);
System.out.println("policies = " + policies);
}
public int discount(Member member, int price, String discountCode) {
DiscountPolicy discountPolicy = policyMap.get(discountCode);
System.out.println("discountCode = " + discountCode);
System.out.println("discountPolicy = " + discountPolicy);
return discountPolicy.discount(member, price);
}
}
}
โ ์คํ ๊ฒฐ๊ณผ
policyMap = {fixDiscountPolicy=study.springstudy.domain.service.discount.FixDiscountPolicy@46292372, rateDiscountPolicy=study.springstudy.domain.service.discount.RateDiscountPolicy@126be319}
policies = [study.springstudy.domain.service.discount.FixDiscountPolicy@46292372, study.springstudy.domain.service.discount.RateDiscountPolicy@126be319]
discountCode = fixDiscountPolicy
discountPolicy = study.springstudy.domain.service.discount.FixDiscountPolicy@46292372
- ์ฌ๊ธฐ์ Map์ ํ์ฉํ ๊ฒ์ ๋ณผ ์ ์๋ค. ์ด๋ DiscountPolicy ํ์ ์ ๊ฐ์ง ๋ชจ๋ ๋น์ด ์ฃผ์ ๋๋ค.
- ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด policyMap์ DiscountPolicy ํ์ ์ธ FixDiscountPolicy, RateDiscountPolicy๊ฐ ์ฃผ์ ๋์๋ค.
- Map์ผ๋ก๋ ๋ฐ์ ์ ์๊ณ , List๋ก๋ ๋ฐ์ ์ ์๋ค. Map์ ๋น์ ์ด๋ฆ๊ณผ ๋น์, List๋ ๋น์ ๋ฆฌํดํ๋ค.
- ์ฌ๊ธฐ์ ์กฐํ๋๋ ํ์ ์ด ์์ผ๋ฉด ๋น ์ปฌ๋ ์ ์ด ๋ฐํ๋๋ค.
- ์ฝ๋์์๋ ๋น ์ด๋ฆ์ ๋๊ฒจ์ policyMap์์ ๊บผ๋ด์ ํ ์ธ ์ ์ฑ ์ ๊ฒฐ์ ํ๋ค.
- fix๋ฅผ ๋๊ฒผ๊ธฐ ๋๋ฌธ์, ๊ณ ์ ๊ธ์ก์ธ 1000์์ ํ ์ธ๋ฐ์ discountPrice๊ฐ 1000์ด ๋๋ค.
๋ค์ ํฌ์คํ ์์๋ ๋น์ ์๋ช ์ฃผ๊ธฐ, ๋น ์ค์ฝํ์ ๋ํด์ ๋ค๋ฃจ๋๋ก ํ๊ฒ ๋ค.
'Back-end > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring] WAS, ์๋ธ๋ฆฟ, ๋ฉํฐ ์ค๋ ๋์ ์ค๋ ๋ ํ (0) | 2022.08.08 |
---|---|
[Spring] ๋น ์๋ช ์ฃผ๊ธฐ ์ฝ๋ฐฑ, ๋น ์ค์ฝํ (0) | 2022.08.07 |
[Spring] ์คํ๋ง์ ์ด์ฉํด ํ์-์ฃผ๋ฌธ ์๋น์ค ๊ฐ๋ฐ, ์คํ๋ง ์ปจํ ์ด๋์ ์ฑ๊ธํค (0) | 2022.08.06 |
[Spring] ์์ ์๋ฐ๋ก ํ์-์ฃผ๋ฌธ ์๋น์ค ๊ฐ๋ฐํ๊ธฐ (0) | 2022.08.06 |
[Spring] ์คํ๋ง์ด๋? (3) | 2022.08.06 |