DevLog ๐Ÿ˜ถ

[Spring] ์ปดํฌ๋„ŒํŠธ ์Šค์บ”๊ณผ ์˜์กด๊ด€๊ณ„ ์ž๋™ ์ฃผ์ž… ๋ณธ๋ฌธ

Back-end/Spring

[Spring] ์ปดํฌ๋„ŒํŠธ ์Šค์บ”๊ณผ ์˜์กด๊ด€๊ณ„ ์ž๋™ ์ฃผ์ž…

dolmeng2 2022. 8. 7. 16:18

- ๊น€์˜ํ•œ ๋‹˜์˜ '์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ - ๊ธฐ๋ณธํŽธ'์„ ๋ณด๊ณ  ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค ๐Ÿ˜Š

 

์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ - ๊ธฐ๋ณธํŽธ - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

์Šคํ”„๋ง ์ž…๋ฌธ์ž๊ฐ€ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๊ฐ€๋ฉด์„œ ์Šคํ”„๋ง์˜ ํ•ต์‹ฌ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๊ณ , ์Šคํ”„๋ง ๊ธฐ๋ณธ๊ธฐ๋ฅผ ํ™•์‹คํžˆ ๋‹ค์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค., - ๊ฐ•์˜ ์†Œ๊ฐœ | ์ธํ”„๋Ÿฐ...

www.inflearn.com


- ์ง€๋‚œ ํฌ์ŠคํŒ…๊ณผ ์ด์–ด์ง‘๋‹ˆ๋‹ค :D

 

[Spring] ์Šคํ”„๋ง์„ ์ด์šฉํ•ด ํšŒ์›-์ฃผ๋ฌธ ์„œ๋น„์Šค ๊ฐœ๋ฐœ, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ์‹ฑ๊ธ€ํ†ค

- ๊น€์˜ํ•œ ๋‹˜์˜ '์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ - ๊ธฐ๋ณธํŽธ'์„ ๋ณด๊ณ  ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค ๐Ÿ˜Š ์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ - ๊ธฐ๋ณธํŽธ - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜ ์Šคํ”„๋ง ์ž…๋ฌธ์ž๊ฐ€ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๊ฐ€๋ฉด์„œ ์Šคํ”„๋ง์˜ ํ•ต์‹ฌ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๊ณ , ์Šคํ”„๋ง

cl8d.tistory.com

 

| ์ปดํฌ๋„ŒํŠธ ์Šค์บ”

- ์ง€๋‚œ ํฌ์ŠคํŒ…๊นŒ์ง€ ์šฐ๋ฆฌ๋Š” 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์ด ๋œ๋‹ค.

 

 

๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ๋Š” ๋นˆ์˜ ์ƒ๋ช…์ฃผ๊ธฐ, ๋นˆ ์Šค์ฝ”ํ”„์— ๋Œ€ํ•ด์„œ ๋‹ค๋ฃจ๋„๋ก ํ•˜๊ฒ ๋‹ค.

Comments