Spring Singleton

Spring์—์„œ์˜ singleton pattern์„ ์•Œ์•„๋ณด๊ธฐ ์ด์ „์—

๋ฅผ ์„ ํ–‰ํ•˜๋ฉด ๋” ์ดํ•ดํ•˜๋Š”๋ฐ ์ข‹๋‹ค.

Singleton Container

์Šคํ”„๋ง์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ณ„๋‹ค๋ฅธ ์„ค์ •์„ ํ•˜์ง€ ์•Š์œผ๋ฉด ๋‚ด๋ถ€์—์„œ ์ƒ์„ฑํ•˜๋Š” ๋นˆ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋ชจ๋‘ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๋งŒ๋“ ๋‹ค.

์Šคํ”„๋ง์€ ์„œ๋ฒ„ ํ™˜๊ฒฝ์—์„œ ์‹ฑ๊ธ€ํ†ค์ด ๋งŒ๋“ค์–ด์ ธ ์„œ๋น„์Šค ์˜ค๋ธŒ์ ํŠธ ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์€ ์ ๊ทน ์ง€์ง€ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์ž๋ฐ”์˜ ๊ธฐ๋ณธ์ ์ธ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ๊ตฌํ˜„ ๋ฐฉ์‹์€ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋‹จ์ ์ด ์žˆ๊ธฐ๋•Œ๋ฌธ์— ์Šคํ”„๋ง์€ ์ง์ ‘ ์‹ฑ๊ธ€ํ†ค ํ˜•ํƒœ์˜ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

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

Singleton Registry์˜ ์žฅ์ ์€ ํ‰๋ฒ”ํ•œ ์ž๋ฐ” ํด๋ž˜์Šค์ด๋”๋ผ๋„ IoC๋ฐฉ์‹์˜ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•ด ์ƒ์„ฑ๊ณผ ๊ด€๊ณ„์„ค์ •, ์‚ฌ์šฉ ๋“ฑ์— ๋Œ€ํ•œ ์ œ์–ด๊ถŒ์„ ์†์‰ฝ๊ฒŒ ์‹ฑ๊ธ€ํ†ค ๋ฐฉ์‹์œผ๋กœ ๋งŒ๋“ค์–ด์ ธ ๊ด€๋ฆฌ๋˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ๋„ ์ž์œ ๋กญ๊ฒŒ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ณ , ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ๋ชฉ์ ์œผ๋กœ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋Œ€์ฒดํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ„๋‹จํ•˜๋‹ค.

์ฆ‰, ์‹ฑ๊ธ€ํ„ด ํŒจํ„ด์˜ ๋‹จ์ ์„ ํ•ด๊ฒฐํ•˜๋ฉด์„œ ๊ฐ์ฒด๋ฅผ ์‹ฑ๊ธ€ํ†ค ๋ฐฉ์‹์œผ๋กœ ์œ ์ง€ ํ•  ์ˆ˜ ์žˆ๋‹ค.

( 1. ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์œ„ํ•œ ์ง€์ €๋ถ„ํ•œ ์ฝ”๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜์ง€ ์•Š์Œ. 2. DIP, OCP, ํ…Œ์ŠคํŠธ, private ์ƒ์„ฑ์ž๋กœ ๋ถ€ํ„ฐ ์ž์œ ๋กญ๊ฒŒ ์‹ฑ๊ธ€ํ†ค ์‚ฌ์šฉ ๊ฐ€๋Šฅ)

์‹ฑ๊ธ€ํ†ค์ด ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ์„œ๋น„์Šค ํ˜•ํƒœ์˜ ์˜ค๋ธŒ์ ํŠธ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ์—๋Š” stateless ๋ฐฉ์‹์œผ๋กœ ๋งŒ๋“ค์–ด์ ธ์•ผํ•œ๋‹ค. ์ด๋•Œ๋Š” ์ฝ๊ธฐ์ „์šฉ ๊ฐ’์ด๋ผ๋ฉด ์ดˆ๊ธฐํ™” ์‹œ์ ์— ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜์— ์ €์žฅํ•ด๋‘๊ณ  ๊ณต์œ ํ•˜๋Š” ๊ฒƒ์€ ๋ฌธ์ œ ์—†๋‹ค. ๋งŒ์•ฝ ๊ฐ ์š”์ฒญ์— ๋Œ€ํ•œ ์ •๋ณด๋‚˜, DB ์„œ๋ฒ„์˜ ๋ฆฌ์†Œ์Šค๋กœ ๋ถ€ํ„ฐ ์ƒ์„ฑํ•œ ์ •๋ณด๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ๋กœ์ปฌ ๋ณ€์ˆ˜, ๋ฆฌํ„ด ๊ฐ’์„ ์ด์šฉํ•˜๋ฉด ๋œ๋‹ค. ๋ฉ”์†Œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ๋‚˜, ๋ฉ”์†Œ๋“œ ์•ˆ์—์„œ ์ƒ์„ฑ๋˜๋Š” ๋กœ์ปฌ ๋ณ€์ˆ˜๋Š” ๋งค๋ฒˆ ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ €์žฅํ•  ๋…๋ฆฝ์ ์ธ ๊ณต๊ฐ„์ด ๋งŒ๋“ค์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์‹ฑ๊ธ€ํ†ค์ด๋ผ๊ณ  ํ•ด๋„ ๋ฌธ์ œ์—†๋‹ค.

Spring์—์„œ์˜ Singleton Pattern

spring์˜ bean๋“ค์€ Bean Factory์— ์˜ํ•ด์„œ ๊ด€๋ฆฌ๋˜๊ณ  ์žˆ์œผ๋ฉฐ, ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด๋Ÿฌํ•œ bean์˜ ์ƒ๋ช…์ฃผ๊ธฐ์˜ scope๋Š” singleton์„ ๋”ฐ๋ฅด๊ณ  ์žˆ๋‹ค. Spring Boot์—์„œ๋Š” ๋ณ„๋„์˜ ์„ค์ •์ด ์—†๋‹ค๋ฉด, DefaultListableBeanFactory๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉฐ, resolveBean ๋ฉ”์†Œ๋“œ๋ฅผ ๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ๋‹ค.

    @Nullable
    private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
        // 1. ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” bean๋“ค์˜ ์ด๋ฆ„์„ ๊ฒ€์ƒ‰
        NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);

        // 2. ๋“ฑ๋ก๋˜์–ด์žˆ๋‹ค๋ฉด ํ•ด๋‹น bean์„ ๋ฆฌํ„ด(์ธ์Šคํ„ด์Šค)
        if (namedBean != null) {
            return namedBean.getBeanInstance();
        }

        // 3. ๋‹ค๋ฅธ beanfactory์—์„œ ์š”์ฒญํ•œ bean ์ฐพ๊ธฐ    
        BeanFactory parent = getParentBeanFactory();
        if (parent instanceof DefaultListableBeanFactory) {
            return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);
        }
        else if (parent != null) {
            ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
            if (args != null) {
                return parentProvider.getObject(args);
            }
            else {
                return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
            }
        }
        // 4. ์ฐพ์ง€ ๋ชปํ–ˆ์„ ์‹œ null ๋ฐ˜ํ™˜
        return null;
    }

ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์—์„œ๋Š” private static ์ ‘๊ทผ ์ œ์–ด์ž๋ฅผ ํ†ตํ•œ singleton ํŒจํ„ด์€ ์ฐพ์•„๋ณผ ์ˆ˜ ์—†๋‹ค.

์•ˆํ‹ฐ ํŒจํ„ด

์•ˆํ‹ฐ ํŒจํ„ด์ด๋ž€, ์Šต๊ด€์ ์œผ๋กœ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ํŒจํ„ด์ด์ง€๋งŒ ์„ฑ๋Šฅ, ๋””๋ฒ„๊น…, ์œ ์ง€๋ณด์ˆ˜, ๊ฐ€๋…์„ฑ ์ธก๋ฉด์—์„œ ๋ถ€์ •์ ์ธ ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์–ด ์ง€์–‘ํ•˜๋Š” ํŒจํ„ด์ด๋‹ค.

Singleton ํŒจํ„ด์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹จ์ ์ด ์žˆ๋‹ค.

  1. private ์ƒ์„ฑ์ž๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด ์ƒ์†์„ ํ•  ์ˆ˜ ์—†๋‹ค.( ๋‹คํ˜•์„ฑ ์ œ๊ณต ๋ถˆ๊ฐ€๋Šฅ, ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„ ์ ์šฉ ๋ถˆ๊ฐ€)

  2. ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋ ต๋‹ค.

  3. ์„œ๋ฒ„ํ™˜๊ฒฝ์—์„œ๋Š” 1๊ฐœ์˜ instance๋ฅผ ๋ณด์žฅํ•˜์ง€ ๋ชปํ•œ๋‹ค.

  4. ์ „์—ญ ์ƒํƒœ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ”๋žŒ์งํ•˜์ง€ ๋ชปํ•˜๋‹ค.

    • singleton์€ ์–ด๋””์—์„œ๋“ ์ง€ ๋ˆ„๊ตฌ๋‚˜ ์ ‘๊ทผํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๊ฐ์ฒด์ง€ํ–ฅ์—์„œ ๊ถŒ์žฅํ•˜์ง€ ๋˜์ง€ ์•Š๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ์ด๋‹ค.

์ด๋Ÿฌํ•œ ์ด์œ ๋กœ Spring์—์„œ ์ง์ ‘ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉฐ, Singleton Registry ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

Singleton Registry / Singleton Pattern ์ฃผ์˜์ 

๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ํ•˜๋‚˜๋งŒ ์ƒ์„ฑํ•ด์„œ ๊ณต์œ ํ•˜๋Š” ์‹ฑ๊ธ€ํ†ค ๋ฐฉ์‹์€ ์—ฌ๋Ÿฌ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ•˜๋‚˜์˜ ๊ฐ™์€ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋Š” ์ƒํƒœ๋ฅผ ์œ ์ง€ (stateful)ํ•˜๊ฒŒ ์„ค๊ณ„ํ•˜๋ฉด ์•ˆ๋œ๋‹ค. ๋ฌด์ƒํƒœ(stateless)๋กœ ์„ค๊ณ„ํ•ด์•ผ ํ•œ๋‹ค!

  • ํŠน์ • ํด๋ผ์ด์–ธํŠธ์— ์˜์กด์ ์ธ ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์•ˆ๋œ๋‹ค.

  • ํŠน์ • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์•ˆ๋œ๋‹ค!

  • ๊ฐ€๊ธ‰์  ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค.

  • ํ•„๋“œ ๋Œ€์‹ ์— ์ž๋ฐ”์—์„œ ๊ณต์œ ๋˜์ง€ ์•Š๋Š”, ์ง€์—ญ๋ณ€์ˆ˜, ํŒŒ๋ผ๋ฏธํ„ฐ, ThreadLocal ๋“ฑ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

์Šคํ”„๋ง ๋นˆ์˜ ํ•„๋“œ์— ๊ณต์œ  ๊ฐ’์„ ์„ค์ •ํ•˜๋ฉด ์ •๋ง ํฐ ์žฅ์• ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

@Configuration

/**
 * ์• ํ”Œ๋ฆฌ์ผ€์…˜์˜ ์‹ค์ œ ๋™์ž‘์— ํ•„์š”ํ•œ ๊ตฌํ˜„ ๊ฐ์ฒด ์ƒ์„ฑ
 * ์ƒ์„ฑํ•œ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค์˜ ์ฐธ์กฐ๋ฅผ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์ฃผ์ž…ํ•ด์ค€๋‹ค.
 * @Configuration ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ @Bean์ด ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๊ด€๋ฆฌ๋  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.
 */
@Configuration
public class AppConfig {

    @Bean
    public MemberService memberService() {
        System.out.println("call AppConfig.memberService");
        return new MemberServiceImpl(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {
        System.out.println("AppConfig.memberRepository");
        return new MemoryMemberRepository();
    }

    @Bean
    public OrderService orderService(){
        System.out.println("AppConfig.orderService");
        return new OrderServiceImpl(memberRepository(), getDiscountPolicy());
    }

    @Bean
    public DiscountPolicy getDiscountPolicy() {
        return new RateDiscountPolicy();
    }

}
package dh0023.springcore.singleton;

import dh0023.springcore.config.AppConfig;
import dh0023.springcore.member.repository.MemberRepository;
import dh0023.springcore.member.service.MemberServiceImpl;
import dh0023.springcore.order.service.OrderServiceImpl;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class ConfigurationSingletonTest {

    @Test
    void configurationTest() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

        MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
        OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class);
        MemberRepository memberRepository = ac.getBean("memberRepository", MemberRepository.class);

        MemberRepository memberRepository1 = memberService.getMemberRepository();
        MemberRepository memberRepository2 = orderService.getMemberRepository();

        System.out.println("memberRepository = " + memberRepository);
        System.out.println("memberRepository1 = " + memberRepository1);
        System.out.println("memberRepository2 = " + memberRepository2);

        Assertions.assertThat(memberRepository).isSameAs(memberRepository1);
        Assertions.assertThat(memberRepository).isSameAs(memberRepository2);
    }


    @Test
    void configurationDeep() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
        AppConfig bean = ac.getBean(AppConfig.class);

        System.out.println("bean = " + bean.getClass());
        // bean = class dh0023.springcore.config.AppConfig$$EnhancerBySpringCGLIB$$2a067523

    }
}

์ˆœ์ˆ˜ํ•œ ํด๋ž˜์Šค๋ผ๋ฉด class dh0023.springcore.config.AppConfig๋กœ ์ถœ๋ ฅ๋˜์–ด์•ผํ•œ๋‹ค. ํ•˜์ง€๋งŒ, @Configuration ์ด CGLIB ๋ฐ”์ดํŠธ ์ฝ”๋“œ ์กฐ์ž‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด AppConfig ๋ฅผ ์ƒ์†๋ฐ›์€ ์ž„์˜์˜ ํด๋ž˜์Šค(AppConfig@CGLIB)๋ฅผ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค.

@Bean์ด ๋ถ™์€ ๋ฉ”์„œ๋“œ๋งˆ๋‹ค ์ด๋ฏธ ์Šคํ”„๋ง ๋นˆ์ด ์กด์žฌํ•œ๋‹ค๋ฉด, ์กด์žฌํ•˜๋Š” ๋นˆ์„ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๋Š” ๋กœ์ง์ด ํฌํ•จ๋˜์–ด ์žˆ์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋œ๋‹ค.

๋งŒ์•ฝ @Configuration ์„ ์„ค์ •ํ•˜์ง€ ์•Š๊ณ  @Bean ๋นˆ์„ ๋“ฑ๋กํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

/**
 * ์• ํ”Œ๋ฆฌ์ผ€์…˜์˜ ์‹ค์ œ ๋™์ž‘์— ํ•„์š”ํ•œ ๊ตฌํ˜„ ๊ฐ์ฒด ์ƒ์„ฑ
 * ์ƒ์„ฑํ•œ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค์˜ ์ฐธ์กฐ๋ฅผ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์ฃผ์ž…ํ•ด์ค€๋‹ค.
 * @Configuration ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ @Bean์ด ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๊ด€๋ฆฌ๋  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.
 */
public class AppConfig {

    @Bean
    public MemberService memberService() {
        System.out.println("call AppConfig.memberService");
        return new MemberServiceImpl(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {
        System.out.println("AppConfig.memberRepository");
        return new MemoryMemberRepository();
    }

    @Bean
    public OrderService orderService(){
        System.out.println("AppConfig.orderService");
        return new OrderServiceImpl(memberRepository(), getDiscountPolicy());
    }

    @Bean
    public DiscountPolicy getDiscountPolicy() {
        return new RateDiscountPolicy();
    }

}
package dh0023.springcore.singleton;

import dh0023.springcore.config.AppConfig;
import dh0023.springcore.member.repository.MemberRepository;
import dh0023.springcore.member.service.MemberServiceImpl;
import dh0023.springcore.order.service.OrderServiceImpl;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class ConfigurationSingletonTest {

    @Test
    void configurationTest() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

        MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
        OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class);
        MemberRepository memberRepository = ac.getBean("memberRepository", MemberRepository.class);

        MemberRepository memberRepository1 = memberService.getMemberRepository();
        MemberRepository memberRepository2 = orderService.getMemberRepository();

        System.out.println("memberRepository = " + memberRepository);
        System.out.println("memberRepository1 = " + memberRepository1);
        System.out.println("memberRepository2 = " + memberRepository2);

        Assertions.assertThat(memberRepository).isSameAs(memberRepository1);
        Assertions.assertThat(memberRepository).isSameAs(memberRepository2);
    }


    @Test
    void configurationDeep() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
        AppConfig bean = ac.getBean(AppConfig.class);

        System.out.println("bean = " + bean.getClass());
        // bean = class dh0023.springcore.config.AppConfig

    }
}

@Configuration์„ ๋“ฑ๋กํ•˜์ง€ ์•Š์•„๋„, @Bean์œผ๋กœ ์Šคํ”„๋ง ๋นˆ๋“ฑ๋ก์ด ๊ฐ€๋Šฅํ•˜๋‚˜, ๋ฐ”์ดํŠธ ์กฐ์ž‘์„ ํ•˜์ง€ ์•Š๋Š” Class๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค. ๋˜ํ•œ, ์‹ฑ๊ธ€ํ†ค์ด ๋ณด์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค.

์ฐธ๊ณ 

Last updated