스프링 컨테이너와 싱글톤 패턴

이동건·2021년 4월 8일
0

Spring

목록 보기
2/5

스프링 컨테이너

스프링 컨테이너는 무엇을 말하는가?

BeanFactory와 ApplicationContext를 말한다.

사실은 BeanFactory를 말하는 거긴 하지만 ApplicationContext도 스프링 컨테이너라고 한다.

그 이유가 뭘까?

ApplicationContext는 인터페이스를 다중 상속 받는데 그 중 하나가 BeanFactory이기 때문이다.

ApplicationContext는 그 외에 다양한 기능들, 예를 들면 MessageSource, EnvironmentCapable, ApplicationEventPublicsher, ResourceLoader 같은 것들도 함께 상속을 받아 사용하게 된다.

하지만 BeanFactory도 상속받아 사용하기 때문에 스프링 컨테이너라고 부를 수 있다.

싱글톤 패턴은 왜 필요한가?

우리가 설정 파일을 통해 의존성을 주입받고, 그에 따라 객체가 자동 생성 될 때, 싱글톤 패턴이 적용되지 않는다면 요청이 하나 올 때 마다 객체를 새로 생성하게 된다. (new 키워드에 의해)

이렇게 생성된 객체는 메모리에 적재되고 수많은 요청에 따라 기하급수적으로 객체의 수가 늘어나게 되며 이는 메모리 낭비로 이어진다.

이 문제를 해결하기 위한 방법이 싱글톤 패턴이다.

하나의 객체를 생성한 후, 요청이 들어오면 그 하나의 객체를 재사용하는 방법이다.

즉, JVM 위에 객체의 수는 단 하나여야 한다.

이를 위해서는 객체가 2개 생성되는 것을 막아야 하며 이를 구현하는 여러 방법이 있지만 가장 대표적인 방법은 생성자를 private으로 만들고 private static 영역에 객체를 하나만 생성해 public static 메소드를 통해서만 조회할 수 있도록 하는 것이다.

이와 같이 구현하면 new 키워드를 통한 객체 생성은 불가능하며 static 영역의 하나의 객체로만 조회하여 사용할 수 있게 된다.

또한 싱글톤은 stateless하게 구현해야 오류가 발생하지 않는다. stateful 하게 되면 중간에 다른 요청에 의해 작업이 끝나기 전에 state가 바뀌는 에러가 생길 수 있다.

싱글톤 패턴의 문제점

객체를 재사용 함으로써 많은 이득을 얻는 싱글톤 패턴은 그만큼 많은 문제점이 존재한다.

우선 싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다. 또한 의존관계상 클라이언트가 구체 클래스에 의존하게 되고 이는 DIP를 위반으로 이어진다. 그리고 클라이언트가 구체 클래스에 의존하기 때문에 OCP 원칙을 위반할 가능성이 높아진다.

그 뿐 아니라 테스트하기 어려우며 내부 속성을 변경하거나 초기화 하기 어렵고 private 생성자로 자식 클래스를 만들기 어렵다.

즉, 결론적으로 유연성이 떨어진다.

스프링에서의 싱글톤 패턴

스프링에서는 이와 같은 싱글톤 패턴의 문제점을 한번에 모두 해결하고 객체의 재사용이라는 장점만 가져와 사용할 수 있도록 하고 있다.

그 방법이 바로 싱글톤 컨테이너 역할을 하는 스프링 컨테이너이다.

스프링 컨테이너는 싱글톤 패턴의 문제점을 해결하면서, 객체 인스턴스를 싱글톤(1개만 생성)으로 관리한다.

스프링 빈이 바로 싱글톤으로 관리되는 빈이다.

@Configuration과 CGLIB

우리가 설정 파일에 @Configuration을 붙일 때, 빈들이 싱글톤으로 관리되게 된다.

스프링이 자바 코드 자체를 바꾸기는 사실상 어렵다. 그래서 채택한 방법이 클래스의 바이트 코드를 조작하는 것이다.

그리고 이 때 사용하는 라이브러리가 CGLIB가 된다.

우리가 생성한 config 파일에 @Configuration이 붙는다면 스프링은 해당 config파일을 그대로 사용하지 않는다.

스프링이 CGLIB라는 바이트코드 조작 라이브러리를 사용해서 config 클래스를 상속받은 임의의 다른 클래스를 만들고, 그 다른 클래스를 스프링 빈으로 등록하여 사용하게 된다.

그리고 그 임의의 다른 클래스가 싱글톤 패턴이 유지되도록 해 준다.

그 임의의 다른 클래스 내부에서의 동작을 추측하면 우선 호출된 빈에 대해 스프링 컨테이너 내부를 찾아 있다면 반환한다.

하지만 스프링 컨테이너 내부에 존재하지 않는다면 해당 빈을 생성하고 스프링 컨테이너에 등록해 주는 작업을 할 것으로 예상할 수 있다.

이를 통해 CGLIB에 의해 생성된 config 클래스는 빈에 대해 스프링 컨테이너를 먼저 찾아 있으면 반환함으로써 싱글톤 패턴을 유지시켜 주는 것이다.

여기서 우리가 config 파일을 조회 할 때 그럼 왜 CGLIB가 생성한 config파일이 조회 되는가에 대한 것은 CGLIB가 생성한 config파일은 그냥 config 파일을 상속받은 자식 파일이기 때문이다. 부모를 조회하면 자식은 따라 출력되기 때문에 조회할 수 있음을 알 수 있다.

끝으로...

위의 사항들을 종합하였을 때, 스프링 컨테이너는 싱글톤 컨테이너의 역할을 겸함으로써 싱글톤 패턴이 유지되도록 해 준다.

싱글톤 패턴은 객체를 하나만 생성해 재사용 함으로써 낭비되는 메모리를 절약할 수 있다.

@Configuration이 붙음으로써 빈들을 호출했을 때 스프링 컨테이너 내부를 먼저 찾아보고 존재한다면 그대로 반환, 없다면 생성해서 넣어주는 것으로 싱글톤을 유지할 수 있었다.

profile
코드를 통한 세계의 창조

0개의 댓글