- 애플리케이션은 보통 다수의 클라이언트들이 요청을 보냄, 매 요청마다 서버에 객체를 생성해서 전달하는 것은 메모리 낭비가 심함

 

public class AppConfig {

    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }

    public OrderService orderService() {
        return new OrderServiceImpl(new MemoryMemberRepository(), new RateDiscountPolicy());
    }

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

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

}
public class MemberApp {

    public static void main(String[] args) {       
        AppConfig appConfig = new AppConfig();
        MemberService memberService = appConfig.memberService();        

        Member member = new Member(1, "memberA", Grade.VIP);
        memberService.join(member);

        Member findMember = memberService.findMember(1L);
        System.out.println("findMember.getName() = " + findMember.getName());
        System.out.println("findMember.getName() = " + findMember.getGrade());
    }

}

- 위와 같이 스프링을 사용하지 않은 AppConfig는 클라이언트에서 매번 new를 통해 새로운 객체를 생성하게 됨

 

 

싱글톤 패턴

- 최초에 static영역에 객체를 1개만 생성

- 외부에서는 getInstance() 메서드를 통해서만 객체를 받아갈 수 있도록 만듦

- 외부에서 생성자 호출을 못하도록 private생성자를 만들어 둠

public Class SingleTonService() {

	private static final SingleTonService instance = new SingleTonService();
    
    public static SingleTonService getInstance() {
    	return instance;
    }
    
    private SingleTonService(){}
    
}

 

스프링 컨테이너는 스프링 빈을 싱글톤으로 관리함

- 스프링 컨테이너에서는 직접 코드로 싱글톤을 구현하지 않아도 알아서 Bean을 하나만 생성해서 싱글톤으로 관리함

- 스프링 컨테이너를 사용하면 웹 애플리케이션에서 직접 싱글톤 구현 없이 간편하게 객체들을 싱글톤으로 관리할 수 있음

public class SingleTonTest {

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

        MemberService memberService1 = ac.getBean("memberService", MemberService.class);
        MemberService memberService2 = ac.getBean("memberService", MemberService.class);

        System.out.println("memberService1 = " + memberService1);
        System.out.println("memberService2 = " + memberService2);

        Assertions.assertThat(memberService1).isSameAs(memberService2);

    }
    
}
memberService1 = com.example.member.MemberServiceImpl@5aac4250
memberService2 = com.example.member.MemberServiceImpl@5aac4250

 

CGLIB

- @Configuration을 사용하면 CGLIB를 사용함

- 스프링 컨테이너가 싱글톤 보장을 위해서 각 클래스를 싱글톤 패턴으로 코드를 생성하지 않고, 바이트코드를 조작하는 CGLIB 라이브러리를 사용

- 스프링 컨테이너는 AppConfig를 그냥 사용하지 않고, CGLIB를 활용하여 설정 클래스 AppConfig를 상속받는 임의의 클래스인 AppConfig$$EnhancerBySpringCGLIB$$6de7d4d1를 만들어서 스프링 Bean으로 등록

- AppConfig$$EnhancerBySpringCGLIB$$6de7d4d1 에는 스프링 Bean등록 작업을 할 때, 이미 스프링 컨테이너에 있으면, 존재하던 Bean을 반환, 없으면 생성해서 등록하는 코드가 생성되었을 것임..

public class MemberTest {

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

        System.out.println("appConfig.getClass() = " + appConfig.getClass());       
    }
}
appConfig.getClass() = class com.example.demo.AppConfig$$EnhancerBySpringCGLIB$$6de7d4d1