DevLog ๐Ÿ˜ถ

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

Back-end/Spring

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

dolmeng2 2022. 8. 6. 22:56

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

 

 

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

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

www.inflearn.com


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

 

[Spring] ์ˆœ์ˆ˜ ์ž๋ฐ”๋กœ ํšŒ์›-์ฃผ๋ฌธ ์„œ๋น„์Šค ๊ฐœ๋ฐœํ•˜๊ธฐ

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

cl8d.tistory.com

- ์ง€๋‚œ ํฌ์ŠคํŒ…์—์„œ, ์ˆœ์ˆ˜ ์ž๋ฐ”๋งŒ์„ ์ด์šฉํ•ด ํšŒ์› - ์ฃผ๋ฌธ, ๊ทธ๋ฆฌ๊ณ  ํ• ์ธ ์„œ๋น„์Šค๋ฅผ ๊ฐœ๋ฐœํ•˜์˜€๋‹ค.

- SRP, OCP, DIP๋ฅผ ๋งŒ์กฑํ•˜๋„๋ก ์„ค๊ณ„ํ•˜์˜€์œผ๋‚˜, ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ Config๋ฅผ ๊ด€๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๋“ฑ ๋ฒˆ๊ฑฐ๋กœ์šด ๋ถ€๋ถ„๋“ค์ด ์ƒ๊ฒผ๋‹ค.

- ๊ทธ๋Ÿฌ๋‚˜, ์Šคํ”„๋ง์—์„œ๋Š” ์ด๋ฅผ ๋‹ค ํ”„๋ ˆ์ž„์›Œํฌ ๋‹จ์œ„๋กœ ๋„˜๊ธฐ๊ธฐ ๋•Œ๋ฌธ์—, ์‚ฌ์šฉ์ž๊ฐ€ ์˜์กด๊ด€๊ณ„๋ฅผ ๋น„๊ต์  ๋œ ์‹ ๊ฒฝ์จ๋„ ๋œ๋‹ค!

 

 

| ์ œ์–ด์˜ ์—ญ์ „ - IoC (Inversion of Control)

- ๊ธฐ์กด์—๋Š” ํ”„๋กœ๊ทธ๋žจ์˜ ์ œ์–ด ํ๋ฆ„์„ AppConfig๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ์—ˆ๋‹ค. ๊ฐ ํด๋ผ์ด์–ธํŠธ๋Š” ์–ด๋–ค ๊ตฌํ˜„ ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด์˜ค๋Š”์ง€ ๋ชจ๋ฅธ๋‹ค!

- ์ด๋Ÿฐ ์‹์œผ๋กœ, ํ”„๋กœ๊ทธ๋žจ์˜ ์ œ์–ด ํ๋ฆ„์„ ์™ธ๋ถ€์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ œ์–ด์˜ ์—ญ์ „์ด๋‹ค.

    - ์ฐธ๊ณ ๋กœ, ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ์ œ์–ดํ•˜๊ณ  ์‹คํ–‰ํ•œ๋‹ค๋ฉด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์•„๋‹Œ 'ํ”„๋ ˆ์ž„์›Œํฌ'๋ผ๊ณ  ํ•œ๋‹ค.

    - ๊ทธ๋Ÿฐ ์˜๋ฏธ๋กœ ์Šคํ”„๋ง ์—ญ์‹œ ์ผ์ข…์˜ ํ”„๋ ˆ์ž„์›Œํฌ์ด๋‹ค. 

 

 

| ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… - DI (Dependency Injection)

- ์ •์ ์ธ ํด๋ž˜์Šค ์˜์กด๊ด€๊ณ„ : ์‹คํ–‰ํ•˜์ง€ ์•Š์•„๋„ ์˜์กด๊ด€๊ณ„ ๋ถ„์„ ๊ฐ€๋Šฅ.

    - ๋‹จ์ˆœํžˆ OrderServiceImpl์ด MemberRepository์™€ DiscountPolicy๋ฅผ ์˜์กดํ•˜๊ณ  ์žˆ์Œ.

- ๋™์ ์ธ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ์˜์กด๊ด€๊ณ„ : ์‹คํ–‰ ์‹œ์ ์— ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์™ธ๋ถ€์—์„œ ์ƒ์„ฑํ•˜๊ณ , ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌํ•ด์„œ ์˜์กด๊ด€๊ณ„ ์—ฐ๊ฒฐ

    - ์‹ค์ œ๋กœ DiscountPolicy์— Fix๊ฐ€ ๋“ค์–ด๊ฐˆ์ง€, Rate๊ฐ€ ๋“ค์–ด๊ฐˆ์ง€.

    - ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๊ฐ ์ฐธ์กฐ๊ฐ’์„ ์ „๋‹ฌํ•ด์„œ ์—ฐ๊ฒฐํ•œ๋‹ค.

- ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด, ์ •์ ์ธ ํด๋ž˜์Šค ์˜์กด๊ด€๊ณ„๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ , ๋™์ ์ธ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ์˜์กด๊ด€๊ณ„๋ฅผ ์‰ฝ๊ฒŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿšฉ AppConfig์ฒ˜๋Ÿผ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋ฉด์„œ, ์˜์กด๊ด€๊ณ„๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ๊ฒŒ IoC Container / DI Container๋ผ๊ณ  ํ•œ๋‹ค.


- ์ด์ œ, ์šฐ๋ฆฌ๊ฐ€ ์งฐ๋˜ ์ฝ”๋“œ์— ์Šคํ”„๋ง์„ ์ ์šฉํ•ด๋ณด์ž.

[AppConfig.java]

@Configuration
public class AppConfig {
    @Bean
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }

    @Bean
    public OrderService orderService() {
        return new OrderServiceImpl(
                memberRepository(),
                discountPolicy()
        );
    }

    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

    @Bean
    public DiscountPolicy discountPolicy() {
        return new FixDiscountPolicy();
    }
}

- @Configuration, @Bean์ด๋ผ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

- ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— @Bean์ด ๋ถ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค!

 

- ์ด๋ ‡๊ฒŒ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ ์นœ๊ตฌ๋ฅผ ๊บผ๋‚ด๊ธฐ ์œ„ํ•ด์„œ๋Š”, ApplicationContext๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

public class MemberApp {
    public static void main(String[] args) {
        ApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(AppConfig.class);
        MemberService memberService =
                applicationContext.getBean("memberService", MemberService.class);
    }
}

- ์—ฌ๊ธฐ์„œ ApplicationContext๊ฐ€ ๋ฐ”๋กœ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์ด๋ฉฐ, ์ด๋•Œ ๊ตฌ์„ฑ ์ •๋ณด๋กœ @Configuration์ด ๋ถ™์€ AppConfig๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

- โœ” ์ดํ›„, @Bean์ด ๋ถ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ๋ชจ๋‘ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐ˜ํ™˜๋œ ๊ฐ์ฒด๋ฅผ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋กํ•˜๋ฉฐ, ๊ฐ๊ฐ์€ ์Šคํ”„๋ง ๋นˆ์ด ๋œ๋‹ค.

- @Bean์ด ๋ถ™์€ ๋ฉ”์„œ๋“œ ๋ช…์ด ๊ณง ๋นˆ์˜ ์ด๋ฆ„์ด ๋œ๋‹ค. ac.getBean(bean_name)์œผ๋กœ ์ฐพ์•„์˜ฌ ์ˆ˜ ์žˆ๋‹ค!

 

- ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋กœ ๊ด€๋ฆฌํ•˜๋ฉด ๋ญ๊ฐ€ ์ข‹์„๊นŒ?

 


| ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ (ApplicationContext)

- ApplicationContext๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋˜์–ด ์žˆ์œผ๋ฉฐ, XML, ํ˜น์€ ์• ๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์˜ ์ž๋ฐ” ์„ค์ • ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

   - ์š”์ฆ˜์€ XML๋ณด๋‹ค๋Š” ๋Œ€๋ถ€๋ถ„ ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด์„œ ๋งŒ๋“œ๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

 

โœ” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

- ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ ์‹œ, ๊ตฌ์„ฑ ์ •๋ณด๋ฅผ ์ง€์ •ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. 

- ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€์˜ ๋นˆ ์ €์žฅ์†Œ์—๋Š” ๋นˆ ์ด๋ฆ„๊ณผ ์‹ค์ œ ๋นˆ ๊ฐ์ฒด ์ฃผ์†Œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

 

โœ” ์Šคํ”„๋ง ๋นˆ ๋“ฑ๋ก

- ์„ค์ • ์ •๋ณด ํด๋ž˜์Šค์— ๋“ฑ๋ก๋œ @Bean ๋ฉ”์„œ๋“œ ์ •๋ณด๋ฅผ ํ†ตํ•ด ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•œ๋‹ค.

- ๋นˆ ์ด๋ฆ„์€ ๋ฉ”์„œ๋“œ ์ด๋ฆ„ or @Bean(name="") ์ˆ˜๋™ ์ง€์ • ๊ฐ€๋Šฅ!

๐Ÿšฉ ๋นˆ ์ด๋ฆ„์€ ํ•ญ์ƒ ๋‹ค๋ฅธ ์ด๋ฆ„์„ ๋ถ€์—ฌํ•ด์•ผ ํ•œ๋‹ค. ์•„๋‹ˆ๋ฉด ์‹คํ–‰ํ•  ๋•Œ ์—๋Ÿฌ๋‚œ๋‹ค...! (๊ทธ๋ž˜์„œ ์›ฌ๋งŒํ•˜๋ฉด ์ˆ˜๋™ ์ง€์ • ์•ˆ ํ•˜๋Š” ๊ฒŒ ๋‚˜์„ ๋“ฏ)

 

โœ” ์Šคํ”„๋ง ๋นˆ ์˜์กด๊ด€๊ณ„ ์„ค์ • - ์ค€๋น„

- ๊ฐ ๋นˆ์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

๐ŸŽˆ์ค€๋น„ ๋‹จ๊ณ„์™€ ์™„๋ฃŒ ๋‹จ๊ณ„๋ฅผ ๋‚˜๋ˆ„์–ด๋‘์—ˆ๋‹ค. ์ด์œ ๋Š” ์ถ”ํ›„ ํฌ์ŠคํŒ…์œผ๋กœ ๋‹ค๋ฃจ๊ฒ ๋‹ค.

 

โœ” ์Šคํ”„๋ง ๋นˆ ์˜์กด๊ด€๊ณ„ ์„ค์ • - ์™„๋ฃŒ

- ์„ค์ • ์ •๋ณด๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ•œ๋‹ค.

 

 

- ์‹ค์ œ๋กœ, ์ฝ”๋“œ์—์„œ ์šฐ๋ฆฌ๊ฐ€ ๋“ฑ๋กํ•œ ๋นˆ์„ ํ™•์ธํ•ด๋ณด์ž.

[ApplicationContextInfoTest.java]

public class ApplicationContextInfoTest {
    AnnotationConfigApplicationContext ac
            = new AnnotationConfigApplicationContext(AppConfig.class);

    @Test
    public void findAllBean() throws Exception {
        // given
        String[] names = ac.getBeanDefinitionNames();
        List<String> registBean = new ArrayList<>();

        System.out.println("get All Bean");
        for(String name: names) {
            Object bean = ac.getBean(name);
            BeanDefinition definition = ac.getBeanDefinition(name);
            System.out.println("name = " + name + " bean = " + bean);
            if(definition.getRole() == BeanDefinition.ROLE_APPLICATION) {
                registBean.add(name);
            }
        }
        System.out.println("์ง์ ‘ ๋“ฑ๋กํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นˆ");
        for(String name : registBean) {
            System.out.println("name = " + name);
        }
    }
}

โœ” ์‹คํ–‰ ๊ฒฐ๊ณผ

<get All Bean>
name = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
bean = org.springframework.context.annotation.ConfigurationClassPostProcessor@27a0a5a2

name = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
bean = org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@7692cd34

name = org.springframework.context.annotation.internalCommonAnnotationProcessor
bean = org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@33aa93c

name = org.springframework.context.event.internalEventListenerProcessor
bean = org.springframework.context.event.EventListenerMethodProcessor@32c0915e

name = org.springframework.context.event.internalEventListenerFactory
bean = org.springframework.context.event.DefaultEventListenerFactory@106faf11

name = appConfig
bean = study.springstudy.config.AppConfig$$EnhancerBySpringCGLIB$$33662889@70f43b45

name = memberService
bean = study.springstudy.domain.service.MemberServiceImpl@26d10f2e

name = orderService
bean = study.springstudy.domain.service.OrderServiceImpl@10ad20cb

name = memberRepository
bean = study.springstudy.domain.repository.MemoryMemberRepository@7dd712e8

name = discountPolicy
bean = study.springstudy.domain.service.discount.FixDiscountPolicy@2c282004

<์ง์ ‘ ๋“ฑ๋กํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นˆ>
name = appConfig
name = memberService
name = orderServicename = memberRepository
name = discountPolicy

 

โœ” ์Šคํ”„๋ง ๋‚ด๋ถ€์—์„œ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋นˆ

- ConfigurationClassPostProcessor

: @Configuration์ด ๋“ฑ๋ก๋œ ๋นˆ ๊ฐ์ฒด์—์„œ @Bean์ด ๋ถ™์–ด ์žˆ๋Š” ๋นˆ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์™€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋กํ•œ๋‹ค.

 

- AutowiredAnnotationBeanPostProcessor

: @Autowired์— ๋Œ€ํ•œ ์˜์กด ์ฃผ์ž… ์ฒ˜๋ฆฌ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค. @Autowired๊ฐ€ ์ ์šฉ๋œ ํ•„๋“œ, ์ƒ์„ฑ์ž, ๋ฉ”์„œ๋“œ์— ์•Œ๋งž์€ ์˜์กด ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…ํ•œ๋‹ค.

 

- CommonAnnotationBeanPostProcessor

: JSR-250 (@PostConstruct ๋“ฑ)์— ๋Œ€ํ•œ ๋ผ์ดํ”„์‚ฌ์ดํด ์ฒ˜๋ฆฌ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค.

 

- EventListenerMethodProcessor

: EventListener ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐœ๋ณ„ ApplicationListener ์ธ์Šคํ„ด์Šค๋กœ ๋“ฑ๋กํ•œ๋‹ค. (๋ถˆํ™•์‹ค)

 

- DefaultEventListenerFactory

: @EventListener๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค. (๋ถˆํ™•์‹ค)

 

 

โœ” ์ง์ ‘ ๋“ฑ๋กํ•œ ๋นˆ

- AppConfig

- memberService -> memberServiceImpl

- orderService -> orderServiceImpl

- memberRepository -> MemoryMemberRepository

- discountPolicy -> FixDiscountPolicy


| ์Šคํ”„๋ง ๋นˆ ์กฐํšŒํ•˜๊ธฐ

- ac.getBean(bean_name, type)

- ac.getBean(type)

: ์ด๋ฆ„+ํƒ€์ž…, ํ˜น์€ ํƒ€์ž…์œผ๋กœ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

@Test
public void findBeanTest() throws Exception {
        // ๋นˆ ์ด๋ฆ„์œผ๋กœ ์กฐํšŒ
        MemberService memberService1 = ac.getBean("memberService", MemberService.class);
        assertThat(memberService1).isInstanceOf(MemberServiceImpl.class);

        // ํƒ€์ž…์œผ๋กœ ์กฐํšŒ
        MemberService memberService2 = ac.getBean(MemberService.class);
        assertThat(memberService2).isInstanceOf(MemberServiceImpl.class);

        // ๊ตฌ์ฒด ํƒ€์ž… ์กฐํšŒ - ์œ ์—ฐ์„ฑ ๋–จ์–ด์ง
        MemberServiceImpl memberService3 = ac.getBean("memberService", MemberServiceImpl.class);
        assertThat(memberService3).isInstanceOf(MemberServiceImpl.class);
        }

- ๋งŒ์•ฝ, ๋™์ผํ•œ ํƒ€์ž…์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋นˆ์ด ์—ฌ๋Ÿฌ ๊ฐœ๊ฐ€ ์กด์žฌํ•œ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ• ๊นŒ?

    - ์ด๋•Œ, ํƒ€์ž… ์กฐํšŒ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. (NoUniqueBeanDefinitionException)

- ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋‘˜ ์ด์ƒ์ผ ๊ฒฝ์šฐ๋Š” ๋นˆ ์ด๋ฆ„ ์กฐํšŒ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. (ac.getBean(bean_name, type))

 

- ๋™์ผํ•œ ํƒ€์ž…์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋นˆ์„ ์กฐํšŒํ•˜๋ ค๋ฉด ac.getBeansOfType()์„ ์‚ฌ์šฉํ•œ๋‹ค.

public class ApplicationContextInfoTest {
    AnnotationConfigApplicationContext ac2 = new
            AnnotationConfigApplicationContext(SameBeanConfig.class);

    @Test
    public void findAllBeanByType() throws Exception {
        Map<String, MemberRepository> beansOfType =
                ac2.getBeansOfType(MemberRepository.class);
        System.out.println("beansOfType = " + beansOfType);
        for(String key : beansOfType.keySet()) {
            System.out.println("key = " + key + " value = " + beansOfType.get(key));
        }
        assertThat(beansOfType.size()).isEqualTo(2);
    }

    @Configuration
    static class SameBeanConfig {
        @Bean
        public MemberRepository memberRepository1() {
            return new MemoryMemberRepository();
        }
        @Bean
        public MemberRepository memberRepository2() {
            return new MemoryMemberRepository();
        }
    }
}

โœ” ์‹คํ–‰ ๊ฒฐ๊ณผ

beansOfType = {memberRepository1=study.springstudy.domain.repository.MemoryMemberRepository@78e16155, memberRepository2=study.springstudy.domain.repository.MemoryMemberRepository@54a3ab8f}
key = memberRepository1 value = study.springstudy.domain.repository.MemoryMemberRepository@78e16155
key = memberRepository2 value = study.springstudy.domain.repository.MemoryMemberRepository@54a3ab8f

- ์ž„์‹œ๋กœ Config ํด๋ž˜์Šค๋ฅผ ์„ ์–ธํ•ด์ค˜์„œ ๋™์ผํ•œ ํƒ€์ž…์„ ๊ฐ€์ง„ ๋นˆ์„ ์ƒ์„ฑํ•˜์˜€๋‹ค.

- ์œ„์ฒ˜๋Ÿผ MemberRepository ํƒ€์ž…์„ ๊ฐ€์ง„ ๋นˆ์ด ์ž˜ ์กฐํšŒ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. (Map ํ˜•ํƒœ๋กœ, ๋นˆ ์ด๋ฆ„๊ณผ ๊ตฌํ˜„์ฒด๊ฐ€ ๋‚˜์˜จ๋‹ค)

 

- ๋˜ํ•œ, ๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ์กฐํšŒ ์‹œ ์ž์‹์ด ๋‘˜ ์ด์ƒ์ด๋ผ๋ฉด ๋นˆ ์ด๋ฆ„ ์กฐํšŒ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋ฉฐ,

์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ์กฐํšŒํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์œ„์ฒ˜๋Ÿผ getBeansOfType()์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.


| BeanFactory vs ApplicationContext

โœ” BeanFactory

: ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ์ตœ์ƒ์œ„ ์ธํ„ฐํŽ˜์ด์Šค. getBean()์„ ์ œ๊ณตํ•œ๋‹ค.

 

โœ” ApplicationContext

: BeanFactory๋ฅผ ์ƒ์†๋ฐ›๋Š”๋‹ค. ๋นˆ ์กฐํšŒ ์™ธ์—๋„ ์ˆ˜๋งŽ์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

- MessageSource : ๊ตญ์ œํ™” ๊ธฐ๋Šฅ (message.properties)

- EnvironmentCapable : profile, property ๊ด€๋ฆฌ ๊ธฐ๋Šฅ.

    - profile : ํŠน์ •ํ•œ ์‹คํ–‰ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋นˆ ๊ทธ๋ฃน ๋‚˜๋ˆ„๊ธฐ (@Profile)

    - property : ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ๋™ ์‹œ ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ key-value ํ˜•ํƒœ๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€ ์ˆœ์œผ๋กœ ๊ฐ€์ ธ์˜จ๋‹ค.

- ApplicationEventPublisher : ์ด๋ฒคํŠธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ํ•„์š”ํ•œ ๊ธฐ๋Šฅ ์ œ๊ณต (@EventListener)

- ResourceLoader : ํŒŒ์ผ, ํด๋ž˜์ŠคํŒจ์Šค, ์™ธ๋ถ€ ๋“ฑ์—์„œ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค. (ResourceLoader.getResource)

 


| BeanDefinition

- ์•ž์„œ ์ž ๊น ์–ธ๊ธ‰ํ•˜์˜€์ง€๋งŒ, ์Šคํ”„๋ง์—์„œ๋Š” ์„ค์ • ์ •๋ณด๋ฅผ xml, ํ˜น์€ ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด์„œ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค.

- ์Šคํ”„๋ง์—์„œ๋Š” ์–ด๋–ป๊ฒŒ ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์„ค์ • ์ •๋ณด๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€์„๊นŒ?

๐Ÿšฉ ๋ฐ”๋กœ, BeanDefinition์„ ํ†ตํ•œ ์ถ”์ƒํ™” ๋•๋ถ„์ด๋‹ค.

- XML์ด๋“ , ์ž๋ฐ” ์ฝ”๋“œ๋“  BeanDefinition์„ ๋งŒ๋“ค๊ธฐ๋งŒ ํ•œ๋‹ค๋ฉด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์˜ค์ง BeanDefinition์„ ์˜์กดํ•œ๋‹ค.

    - BeanDefinition์„ ๋นˆ ์„ค์ • ์ •๋ณด๋ผ๊ณ  ํ•˜๋ฉฐ, @Bean, <bean>๋‹น ํ•˜๋‚˜์”ฉ ๋ฉ”ํƒ€ ์ •๋ณด๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

    - ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์ด๋Ÿฌํ•œ ๋ฉ”ํƒ€ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์Šคํ”„๋ง ๋นˆ์„ ์ƒ์„ฑํ•œ๋‹ค.

 

โœ” ๊ตฌ์ฒด์ ์ธ ์ƒ์„ฑ ๋ฐฉ์‹

- AnnotationConfigApplicationContext๋Š” AnnotatedBeanDefinitionReader๋ฅผ ํ†ตํ•ด์„œ ์ž๋ฐ” ์ฝ”๋“œ ๊ธฐ๋ฐ˜ ์„ค์ • ์ •๋ณด(@Configuration)๋ฅผ ์ฝ์–ด ์ƒ์„ฑ.

- GenericXmlApplicationContext๋Š” XmlBeanDefinitionReader๋ฅผ ํ†ตํ•ด์„œ XML์„ ์ฝ์–ด ์ƒ์„ฑ.

- ์ฆ‰, ์ด๋Ÿฐ ์‹์œผ๋กœ Reader๋ฅผ ํ†ตํ•ด BeanDefinition์„ ๋งŒ๋“ค์–ด์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

 

โœ” BeanDefinition์—” ์–ด๋–ค ์ •๋ณด๋“ค์ด ์žˆ์„๊นŒ?

- BeanClassName : ์ƒ์„ฑํ•  ๋นˆ์˜ ํด๋ž˜์Šค ๋„ค์ž„. (์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์—์„œ๋Š” null)

- factoryBeanName: ํŒฉํ† ๋ฆฌ ์—ญํ• ์˜ ๋นˆ ๋„ค์ž„(appConfig)

- factoryMethodName: ๋นˆ์„ ์ƒ์„ฑํ•  ๋ฉ”์„œ๋“œ (memberService)

- Scope: ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹ฑ๊ธ€ํ†ค์ด๋‹ค.โญ

- lazyInit: ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ ์‹œ ๋นˆ์ด ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ์‹ค์ œ ์‚ฌ์šฉ ์‹œ์ ์— ๋นˆ์„ ์‚ฌ์šฉํ•˜๋„๋ก ์ง€์—ฐ ์ฒ˜๋ฆฌ ์—ฌ๋ถ€

- InitMethodName: ๋นˆ ์ƒ์„ฑ ํ›„ ์˜์กด๊ด€๊ณ„ ์ ์šฉํ–ˆ์„ ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ ๋„ค์ž„

- DestroyMethodName: ๋นˆ ์†Œ๋ฉธ ํ›„ ์ œ๊ฑฐ ์ง์ „์— ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ ๋„ค์ž„

- Constructor arguments, Properties: ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์„ค์ •. (์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์—์„œ๋Š” null)


| Singleton Pattern

- ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” DI ์ปจํ…Œ์ด๋„ˆ์˜ ๊ฒฝ์šฐ, ์‹ฑ๊ธ€ํ†ค์„ ๋ณด์žฅํ•œ๋‹ค.

 

โœ” ์‹ฑ๊ธ€ํ†ค์ด๋ž€?

: ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ 1๊ฐœ๋งŒ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด.

 

โœ” ์‹ฑ๊ธ€ํ†ค์„ ์‹คํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•

public class SingletonService {
    private static final SingletonService service = new SingletonService();

    public static SingletonService getService() {
        return service;
    }

    private SingletonService() {
    }
}

- ์ƒ์„ฑ์ž๋ฅผ private์œผ๋กœ ๋‘์—ˆ๊ธฐ ๋•Œ๋ฌธ์—, SingletonService ๊ฐ์ฒด๋ฅผ ์™ธ๋ถ€์—์„œ new๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค.

- static ์˜์—ญ์— ์„ ์–ธํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ๋”ฑ 1๊ฐœ๋งŒ ์ƒ์„ฑํ•ด๋‘”๋‹ค. final๋กœ ์„ ์–ธํ•œ ๊ฒƒ์€ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์œผ๋‹ˆ๊นŒ.

(๐Ÿšฉ static ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์„ ํ•œ ๋ฒˆ๋งŒ ์ˆ˜ํ–‰ํ•œ๋‹ค = ๊ฐ™์€ ๊ณณ์˜ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋งŒ ๋ฐ”๋ผ๋ณธ๋‹ค.)

- service๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด์„œ getService() ๋ฉ”์„œ๋“œ๋งŒ public์œผ๋กœ ์—ด์–ด๋‘์—ˆ๋‹ค.

์•ž์œผ๋กœ SingletonService์˜ service๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด์„œ๋Š” getService() ๋ฉ”์„œ๋“œ๋กœ๋งŒ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

SingletonService singletonService1 = SingletonService.getInstance();
SingletonService singletonService2 = SingletonService.getInstance();

- ์—ฌ๊ธฐ์„œ singletonService1, 2๋Š” ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋ฅผ ๋ฐ”๋ผ๋ณด๊ฒŒ ๋œ๋‹ค. ๊ฐ™์€ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋‹ˆ๊นŒ!

 

โœ” ๊ทธ๋Ÿฌ๋‚˜, ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์€...

- ์ฝ”๋“œ ๊ตฌํ˜„์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋กœ์ง์ด ์ง€์ €๋ถ„ํ•ด์ง„๋‹ค.

- DIP๋ฅผ ์œ„๋ฐ˜ํ•œ๋‹ค. ๊ตฌ์ฒด ํด๋ž˜์Šค์— ์˜์กดํ•˜๊ธฐ ๋•Œ๋ฌธ์—! -> OCP๋ฅผ ์œ„๋ฐ˜ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

- ํ…Œ์ŠคํŠธํ•˜๊ธฐ๊ฐ€ ์–ด๋ ค์šฐ๋ฉฐ, ๋‚ด๋ถ€ ์†์„ฑ ๋ณ€๊ฒฝ์ด ์–ด๋ ต๋‹ค. -> ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค.

 


- ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ๋ฌธ์ œ์ ์„ ํ•ด๊ฒฐํ•˜๋ฉด์„œ๋„, ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค!

- ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ณง ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋˜๋ฉฐ, ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‹ฑ๊ธ€ํ†ค ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ผ๊ณ  ํ•œ๋‹ค.

- ๋•๋ถ„์— ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์‚ฝ์ž…ํ•  ํ•„์š”๋„ ์—†์œผ๋ฉฐ, DIP, OCP๋กœ๋ถ€ํ„ฐ ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค!

@Test
void springContainer() {
    ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
    MemberService memberService1 = ac.getBean("memberService",
    MemberService.class);
    MemberService memberService2 = ac.getBean("memberService",
    MemberService.class);

    // memberService1 = study.springstudy.domain.service.MemberServiceImpl@6a175569
    System.out.println("memberService1 = " + memberService1);
    // memberService2 = study.springstudy.domain.service.MemberServiceImpl@6a175569
    System.out.println("memberService2 = " + memberService2);

    assertThat(memberService1).isSameAs(memberService2);
}

- ํ™•์ธํ•ด๋ณด๋ฉด, ์š”์ฒญ์ด ์˜ฌ ๋•Œ๋งˆ๋‹ค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ์ด๋ฏธ ๋งŒ๋“ค์–ด์ง„ ๊ฐ์ฒด๋ฅผ ๋‹ค์‹œ ๋ฐ˜ํ™˜ํ•ด์ค€๋‹ค!

 

โœ” ์‹ฑ๊ธ€ํ†ค ์ฃผ์˜์‚ฌํ•ญ

- ํ•˜๋‚˜์˜ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, statelessํ•˜๊ฒŒ ์„ค๊ณ„ํ•ด์•ผ ํ•œ๋‹ค.

- ๊ฐ€๊ธ‰์  ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค. (๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๊ฒŒ ๋˜๋ฉด ์œ„ํ—˜)

- ์Šคํ”„๋ง ๋นˆ์˜ ํ•„๋“œ์— ๊ณต์œ ๊ฐ’์€ ์ ˆ๋Œ€์ ˆ๋Œ€ ์„ค์ •ํ•˜์ง€ ๋ง ๊ฒƒ.

 


| @Configuration๊ณผ Singleton

- ์Šคํ”„๋ง์€ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹ฑ๊ธ€ํ†ค์„ ๋ณด์žฅํ•œ๋‹ค.

@Test
void configurationDeep() {
    ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
    AppConfig bean = ac.getBean(AppConfig.class);
    // bean = class study.springstudy.config.AppConfig$$EnhancerBySpringCGLIB$$30df2dad
    System.out.println("bean = " + bean.getClass());
}

@Configuration์„ ์‚ฌ์šฉํ•˜๋ฉด AppConfig bean์„ ํ™•์ธํ•ด ๋ณด๋ฉด ํ”„๋ก์‹œ ๊ฐ์ฒด์ธ ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋‹ค! (CGLIB)

: ์ฐธ๊ณ ๋กœ, AppConfig@CGLIB๋Š” AppConfig๋ฅผ ์ƒ์†๋ฐ›์•„์„œ ๊ตฌํ˜„ํ•œ๋‹ค. (๊ทธ๋ž˜์„œ AppConfig.class๋กœ getBean ์กฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•œ ๊ฒƒ. ๋ถ€๋ชจ ํƒ€์ž…์ด๋‹ˆ๊นŒ)

์ฆ‰, ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•  ๋•Œ ๋‚ด๋ถ€์ ์œผ๋กœ ์‹ค์ œ AppConfig ๋Œ€์‹  ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋“ฑ๋กํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

๋‚ด๋ถ€์ ์œผ๋กœ @Bean์ด ๋ถ™์€ ๋ฉ”์„œ๋“œ๋งˆ๋‹ค ์ด๋ฏธ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋˜์–ด ์žˆ๋‹ค๋ฉด, ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ฐพ์•„์„œ ๋ฐ˜ํ™˜ํ•ด์ฃผ๊ณ ,

์—†์œผ๋ฉด ๊ธฐ์กด์˜ ๋กœ์ง์„ ํ˜ธ์ถœํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ ๋‹ค์Œ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก์‹œํ‚ค๋Š” ๊ณผ์ •์„ ํ†ตํ•ด ๋™์ ์œผ๋กœ ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋ก ๋ฐ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

๋งŒ์•ฝ, AppConfig์— @Configuration์„ ๋ถ™์ด์ง€ ์•Š๊ณ  ๋‹จ์ˆœํžˆ @Bean๋งŒ ๋ถ™์ด๋ฉด CGLIB์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์‹ฑ๊ธ€ํ†ค ์—ญ์‹œ ๋ณด์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.

๐Ÿšฉ ์ฆ‰, ์‹ค์งˆ์ ์ธ ์‹ฑ๊ธ€ํ†ค ๋ณด์žฅ์€ @Configuration์„ ํ†ตํ•ด ์ด๋ฃจ์–ด์ง€๋ฉฐ, @Bean์€ ์Šคํ”„๋ง ๋นˆ ๋“ฑ๋ก ์—ญํ• ๋งŒ ํ•œ๋‹ค.

 

์šฐ๋ฆฌ๋Š” ์ง€๊ธˆ๊นŒ์ง€ @Configuration, @Bean์„ ํ†ตํ•ด ๋นˆ์„ ๋“ฑ๋กํ•˜์˜€๋Š”๋ฐ, ์ด๋ฅผ ๋” ์ž๋™ํ™”์‹œํ‚ฌ ์ˆ˜๋Š” ์—†์„๊นŒ?

-> ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์„ ์ด์šฉํ•˜์ž! ์ด๋Š” ๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ ๋‹ค๋ฃจ๊ฒ ๋‹ค.

 

Comments