자바생
article thumbnail
728x90

싱글톤 패턴

AppConfig을 보면 객체를 호출할 때마다 새로운 객체를 생성한다.

그렇다면 고객이 동시에 요청을 했다면, 매 호출마다 새로운 객체를 생성해야해서 시간도 오래 걸리고, 메모리 낭비도 시하게 된다.

 

그래서 해당 객체를 한 개만 생성하고, 요청이 들어올 때마다 하나의 객체를 가지고 공유하는 싱글톤 패턴이라는 것이 있다. 

 

싱글톤 패턴이란 클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴이다.

싱글톤 패턴을 적용한 코드는 여러 종류가 있지만 그 중 하나인 private 생성자를 사용하여 외부에서 새로운 클래스 인스턴스를 막는다.

 

SingletonService 객체를 private static final로 선언하고, getInstance 메서드를 통해서만 인스턴스를 얻을 수 있다. 그리고, SingletonService의 생성자는 private이므로 외부 클래스에서 새로운 인스턴스를 생성할 수 없다. 즉, getInstance로만 객체를 얻는데, 여기서 반환하는 instance는 static final이기 때문에 1개의 객체 인스턴스만 존재할 수 있게 된다.

 

하지만 싱글톤 패턴의 단점이 많다. 그 중 제일 중요한 점은 코드 자체가 많이 들어간다라는 점이다,, 그래서 스프링을 사용하면 이 모든 걸 해결해준다고 한다!!

 


스프링을 이용한 싱글톤 컨테이너

위에서 말했듯이 싱글톤 패턴은 항상 코드를 작성해야하고, 작성해야 할 코드의 양이 많다. 그래서 스프링을 사용하면 스프링 자체 컨테이너는 객체 인스턴스를 싱글톤으로 관리한다. 즉, 스프링 컨테이너는 싱글톤 컨테이너 역할을 한다. 

1번과 같이 AppConfig 객체를 생성하고, 싱글톤 패턴 코드를 적용시켜야 객체가 하나만 생성이 되었는데,

2번과 같이 스프링을 이용하면 패턴 코드를 작성하지 않아도 스프링 컨테이너 자체에서 객체 인스턴스를 싱글톤으로 관리하게 된다.

 

앞 강좌에서 굳이 왜 스프링 컨테이너로 바꿀까? 바꾸면 장점이 뭐지? 라는 말씀을 하셨고, 그에 대한 답을 뒤에 강의를 이어나가시면서 하나씩 말씀해주신다고 하셨다. 컨테이너로 바꿀 때 생기는 장점 중의 하나가 싱글톤 컨테이너이다.

 

하지만 이런 편리한 것을 사용하면서 주의할 점이 있다.

객체 인스턴스 하나만 생성해서 공유하기 때문에, 인스턴스 안에 있는 데이터들은 유지가 된다. 

즉, 사용자 A가 만원을 저장하고, 사용자 B가 2만원을 저장했을 때, 사용자 A가 저장한 돈을 출력하면 2만원이 나오게 된다. 

이러한 것을 방지하기 위해 싱글톤 객체는 *무상태(stateless)로 설계해야 한다.

-> 공유 변수를 사용하지 않고, 지역 변수, 파라미터를 사용해야 한다.

 

 

1번과 같이 공유필드변수 price를 선언하여 사용하면 장애가 발생한다. 

그러면 2번과 같이 바로 반환을 시켜 지역변수처럼 사용해야 함으로써 해결할 수 있다.

 

stateless(무상태)

-> 과거에 대한 정보, 데이터가 저장되지 않아서 시작할 때마다 처음부터 시작됨


@Configuration

싱글톤을 누가 계속 유지시키려는 것일까? 바로 @Configuration이다. 

AppConfig을 테스트코드에서 실행시켜보면, 각각의 빈들은 한 번씩 호출이 되고, 

코드 상으로 봤을 땐 여러 번 출력 되는 memberRepository는  한 번씩 호출이 된다.

만약, @Configuration 없이 테스트를 실행하게 되면 코드 그대로 memberRepoository는 여러 번 출력이 된다.

 

@Configuration이 있을 때

memberRepository1 -> memberRepository = hello.core.member.MemoryMemberRepository@2f48b3d2
memberRepository = hello.core.member.MemoryMemberRepository@2f48b3d2

 

@Configuration이 없을 때

memberRepository1 -> memberRepository = hello.core.member.MemoryMemberRepository@3c7c886c
memberRepository = hello.core.member.MemoryMemberRepository@55493582

 

주소 값이 다른 것을 알 수 있다.

 


@Configuration으로 

 

AppConfig의 클래스(@Configuration이 있을 때)

bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$b8933e89

 

AppConfig의 클래스(@Configuration이 없을 때)

bean = class hello.core.AppConfig

 

둘의 차이를 보면 AppConfig 다음에 $$ 하면서 CGLIB ~~ 이런 것이 보인다.

여기서 AppConfig을 상속하는 AppConfig@CGLIB의 인스턴스를 사용하는 것이다.

스프링이 CGLIB라는 것을 이용하여 AppConfig을 상속받은 다른 클래스를 만들고 거기에 스프링 빈을 등록한다.

그래서 빈을 조회할 때, 빈이 있으면 그대로 반환하고 없으면 생성하고 반환한다. 그래서 싱글톤을 유지할 수 있었던 것이다. 

728x90
profile

자바생

@자바생

틀린 부분이 있다면 댓글 부탁드립니다~😀

검색 태그