본문 바로가기
Spring/Basic

@Configuration

by o3oppp 2024. 8. 20.
@Configuration
  • Bean을 등록할 때 싱글톤이 되도록 보장해 주는 어노테이션
  • 스프링 컨테이너에서 Bean을 관리할 수 있게 됨
  • 결론적으로 스프링 설정 정보는 항상 @Configuration 사용

AppConfig

package hello.core;

import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

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

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

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

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

Test

package hello.singleton;

import hello.core.AppConfig;
import hello.core.member.MemberRepository;
import hello.core.member.MemberServiceImpl;
import hello.core.order.OrderServiceImpl;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import static org.assertj.core.api.Assertions.*;

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("memberService -> memberRepository1 = " + memberRepository1);
        System.out.println("orderService -> memberRepository2 = " + memberRepository2);
        System.out.println("memberRepository = " + memberRepository);

        assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
        assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
    }
}

결과

Configuration 적용 전
Configuration 적용 후


바이트코드 조작

인프런 참조

  • 스프링이 CGLIP라는 바이트코드 조작 라이브러리를 사용해서 AppConfig 클래스를 상속받은 임의의 다른 클래스 생성
  • 생성된 다른 클래스를 스프링 빈으로 등록. 해당 클래스가 바로 싱글톤이 보장되도록 해줌

AppConfig@CGLIB 예상 코드

@Bean
 public MemberRepository memberRepository() {
	if (memoryMemberRepository가 이미 스프링 컨테이너에 등록되어 있으면?) { 
    		return 스프링 컨테이너에서 찾아서 반환;
	} else { //스프링 컨테이너에 없으면 기존 로직을 호출해서 MemoryMemberRepository를 생성하고 스프링 컨테이너에 등록
        	return 반환
	}
}
  • @Bean이 붙은 메서드마다 이미 스프링 빈이 존재하면 존재하는 빈을 반환
  • 없으면 생성해서 스프링 빈으로 등록하고 반환
  • 이로 인해 싱글톤이 보장
  • @Bean만 사용해도 스프링 빈으로 등록되지만, 싱글톤을 보장하지는 않음

'Spring > Basic' 카테고리의 다른 글

의존관계 자동 주입  (0) 2024.08.29
@ComponentScan  (0) 2024.08.21
Singleton  (0) 2024.08.20
스프링 컨테이너  (0) 2024.08.17
AppConfig  (0) 2024.08.15