본문 바로가기

[Kotlin&Spring] 5기 내일배움캠프

[Kotlin&Spring] 5기 싱글톤 패턴과 Spring Framework에서 단점 해결 방안

 

싱글톤 패턴(Singleton Pattern)이란,

클래스의 인스턴스가 오직 하나만 생성되도록 보장하는 디자인 패턴이다

 

어플리케이션 전체에서 단 한 개의 객체만 생성해서 사용하고 싶다면 싱글톤 패턴(Singleton Pattern)을 적용할 수 있다

싱글톤 패턴의 핵심은 생성자를 private 접근 제한해서 외부에서 new 연산자로 생성자를 호출할 수 없도록 막는 것이다

예시 코드는 아래와 같다

public class ClassName {

	//private 접근 제한을 갖는 정적 필드 선언과 초기화
    private static ClassName singleton = new ClassName();
    
    //private 접근 제한의 생성자 선언
    private ClassName(){}
    
    //public 접근 권한을 갖는 정적 메소드 선언
    public static ClassName getInstance() {
    	return singleton;
    }
}

 

필드에 private 접근 권한으로 static 변수를 선언한다

이 변수는 자기 자신의 타입의 객체로 초기화된다

private 접근 권한을 갖기 때문에 외부에서 필드 값을 변경할 수 없다

정적 필드값을 반환하는 getInstance()  정적 메소드를 public 으로 선언해 외부에서 객체를 얻을 수 있게 한다

getInstance() 메소드가 리턴하는 객체는 정적 필드가 참조하는 싱글톤 객체이다

따라서 외부에서 사용하는 ClassName 객체는 변수명이 달라도 모두 같은 주소값을 참조하게 된다

즉, stack 영역의 여러 변수들이 모두 Heap영역의 같은 주소 값을 가리킨다

 

Web Application 은 불특정 다수의 고객이 동시에 많은 요청을 보낸다

요청을 할 때마다 객체를 새로 생성하고 처리가 완료하면 객체가 소멸된다

이와 같은 과정은 메모리 낭비를 심하게 한다

 

싱글톤 패턴을 적용하면 객체 인스턴스가 하나만 생성되고 생성된 인스턴스만을 사용하게 한다

객체가 한 번만 생성되어 리소스를 절약할 수 있다

그러나 장점이 있는만큼 단점도 존재한다

 

싱글톤 패턴의 문제점

싱글톤 패턴을 구현하기 위한 코드의 양이 많다

구현 클래스에 의존해 객체 지향 원칙중 DIP와 OCP를 위반한다

유연성이 떨어지기 때문에 안티패턴으로 불리기도 한다

 

의존 역전 원칙, DIP(Dependency Inversion Principle)은 객체에서 어떤 Class 를 참조해야하면 그 Class 직접 참조가 아닌 그 대상의 상위요소(추상 클래스/인터페이스)로 참조하는 것을 말한다
객체들이 정보를 주고 받을 때 의존 관계(한 클래스의 기능 수행 시 다른 클래스의 서비스가 필요한 것)가 형성된다
이 때 추상성이 낮은 클래스보다 추상성이 높은 클래스와 통신을 하는 것을 추구한다

싱글톤 패턴을 사용하면 한 객체의 값을 고정시키고 그 값에 의존하기 때문에 추상화 개념을 구현할 수 없다

 

개방 폐쇄 원칙, OCP(Open Closed Principle)은 기존의 코드를 변경하지 않으면서 기능을 추가할 수 있도록 설계가 되어야한다는 원칙이다
확장(새로운 기능 추가)에 대해서는 개방적, 수정에 대해서는 폐쇄적이어야한다
추상화 개념과 연결되어 다형성과 확장을 가능케하는 객체지향의 장점을 극대화한다

DIP와 같이 OCP도 마찬가지로 싱글톤 패턴과 함께 구현이 어려워진다 

 

Spring 내부에는 싱글톤 컨테이너가 있다

Spring은 Web Application을 만들 때 주로 사용되는데, 싱글톤 패턴의 문제점을 해결하면서 객체를 싱글톤으로 관리한다

Spring Bean은 싱글톤으로 관리되는 객체이다

아래는 스프링 프레임워크에서 싱글톤을 사용하는 코드 예시이다

@Component 어노테이션이나 내부적으로 @Component 어노테이션이 있는 어노테이션을 사용하면 스프링 프레임워크에서 싱글톤으로 객체를 관리해준다

@Service
public class SingletonService {
    //서비스 로직
}

 

 

 

겍체의 인스턴스를 하나만 생성하여 공유하는 싱글톤 패턴의 객체는 상테를 유지(stateful)하면 안된다

상태를 유지 하게 되면 ACID원칙을 위반하고 데이터가 불일치하거나 동시성 문제가 발생할 수 있다

따라서 Spring Bean은 항상 무상태(stateless)가 되도록 설계해야한다

특정 클라이언트에 의존적인 필드가 있거나 변경할 수 있으면 안된다

 

무상태(Stateless)란, 객체가 특정 클라이언트의 상태 정보를 저장하지 않는 것을 말한다

여러 사용자가 같은 객체를 공유하더라도 이전 요청과 다음 요청이 서로 영향을 주지 않도록 설계하는 개념이다

 

무상태를 유지하기 위해서는 객체의 속성을 서비스, 컨트롤러 등에 상태로 저장하지 않고 매개변수나 메소드 내부에 지역변수에 저장하는 방법이 있다

 

객체의 속성을 상태, 클래스의 필드로 저장하면 싱글톤 패턴과 같이 static 키워드가 있을 경우 method 영역에 저장된다

프로그램이 시작되면 클래스가 처음 로드될 때 할당되고, 프로그램이 종료될 때까지 유지된다

지역변수는 메서드 내부에서 선언된 변수이며 stack 영역에 저장된다 변수가 선언된 메서드 실행이 끝나면 자동으로 제거된다

매개변수는 메서드 호출시 전달하는 값을 가지고 있는 인수이다

지역변수와 같이 선언된 곳부터 수행이 끝날 때까지 유효하며 매서드 호출이 끝나면 소멸된다

 

또한 Session을 이용해 사용자의 상태를 서버에 저장할 수 있다

Session은 서버에서 중요한 정보를 보관하며 로그인 연결을 유지하는 방법이다

Session은 Cookie와 다르게 client가 아닌 서버에서 정보를 저장하는 방법이다

Servlet 의 HttpSession은 Session을 간편하게 사용할 수 있도록 다양한 기능을 지원한다

 

하지만 세션에도 문제점이 존재한다

서버가 DB 혹은 메모리에 저장된 세션 정보를 매번 조회하여 오버헤드(Overhead)가 발생한다

오버헤드는 어떤 처리를 하기 위해 들어가는 간접적인 처리 시간, 메모리 등을 의미한다

서버가 상태를 유지해야 하므로 사용자 수가 많아질수록 부담이 커진다

이에 대한 해결방안으로 Token, JWT등의 방식이 있다

 

싱글톤 패턴과 다양한 해결방안을 보면 어플리케이션 제작시 메모리와 성능에 대한 고민을 항상 해야되는 것 같다

하나의 문제에 많은 해결 방법들이 존재하기 때문에 왜 이 방안을 택했는지 생각하는 게 중요한 것 같다

오늘도 하나 알아가서 좋다

내일은 더 열심히 하는 내가 되기를 바란다! 화이팅 ~