0. Intro
<'면접을 위한 CS 전공지식 노트' 1장 디자인 패턴>을 읽으며, 싱글톤 패턴은 스프링 빈, 팩토리 패턴은 스프링 컨테이너가 DI하는 것을 떠올렸다.
내가 이해한 바가 맞는지, 그리고 Spring에서 사용중인 다른 디자인 패턴은 어떤 것들이 있는지 알아보고자 이 글을 작성하게 되었다.
결론부터 얘기하면, 스프링에서는 싱글톤 패턴, 팩토리 메서드 패턴, 프록시 패턴, 템플릿 메서드 패턴을 사용하고 있다.
하나씩 살펴보자.
1. 디자인 패턴(Design Pattern)이란?
우선 디자인 패턴이 무엇이고, 어떤 것들이 있는지 알아보자.
디자인 패턴이란, 프로그램을 설계할 때 발생했던 문제점들을 객체 간의 상호 관계 등을 이용하여 해결할 수 있도록 하나의 '규약' 형태로 만들어 놓은 것을 의미한다.
여러 종류의 디자인 패턴이 있으며, 각각의 상황과 문제에 맞는 디자인 패턴을 적절하게 사용해야 한다.
다음과 같은 디자인 패턴이 존재한다.
- 싱글톤 패턴
- 팩토리 패턴
- 전략 패턴
- 옵저버 패턴
- 프록시 패턴
- 이터레이터 패턴
- 노출 모듈 패턴
- MVC 패턴
- MVP 패턴
- MVVM 패턴
- 템플릿 메소드 패턴
- 퍼사드 패턴
2. 스프링에서 사용되는 디자인 패턴
2-1. 싱글톤 패턴 (singleton pattern)
하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴
데이터베이스 연결 모듈에 많이 쓰인다. 인스턴스 생성 비용이 줄어들지만, 의존성이 높아진다.
그래서 TDD에 어려움이 있다. 단위 테스트는 서로 독립적이고 어떤 순서로든 실행할 수 있어야 하는데 싱글톤 패턴은 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴이므로 '독립적인' 인스턴스를 만들기가 어렵다.
이것을 의존성 주입(DI)로 해결할 수 있다. DI를 통해 모듈간의 결합을 조금 더 느슨하게 만들어 해결할 수 있다. 좀더 구체적으로 설명하자면, 의존성 주입자(dependency injector)가 간접적으로 의존성을 주입하여 메인 모듈(상위 모듈)이 다른 하위 모듈에 대한 의존성을 주지 않도록 하여 의존성을 낮추는 것이다. ('디커플링 된다')
스프링 IoC 컨테이너 당 하나의 객체를 가진다. 기본적으로 스프링의 빈들은 싱글톤으로 되어있다.
객체 주입 시 새로운 객체를 만들도록 설정하고 싶다면, bean scope를 프로토타입으로 변경하면 된다.
만약, 싱글톤 빈이 아닐 경우 발생하는 문제는 다음과 같다.
1. 데이터 일관성 문제
특정 기능을 수행하기 위한 공유 데이터가 있을 경우, 여러 인스턴스가 동시에 접근하여 데이터 불일치가 발생할 수 있다. 예를 들어, 재고가 1개 남아 있을 때 두 사용자가 동시에 주문하면,
- 인스턴스 A가 재고를 조회하고 1이라고 인식하여 차감
- 인스턴스 B도 거의 동시에 재고를 조회하고 1이라고 인식하여 차감
- 결과적으로 재고가 0보다 적게 차감되거나, 두 주문이 모두 성공 처리
이로 인해 실제 데이터베이스와 애플리케이션의 상태가 불일치하게 되고, 재고가 부족한 상태에서 두 개의 주문이 승인되는 데이터 일관성 문제가 발생한다.
2. 메모리 낭비 및 성능 저하
예를 들어 데이터베이스 연결을 관리하는 객체가 여러 개라면, 매번 새로운 객체가 생성되어 연결하게 된다. 불필요한 커넥션 풀링을 발생시켜 리소스 낭비와 성능 저하를 초래할 수 있다.
3. 로깅 일관성 문제
로그를 기록하는 객체가 여러 개일 경우, 동일한 이벤트에 대해 여러 로그 파일에 분산 기록될 수 있어 관리가 어려워진다.
2-2. 팩토리 메소드 패턴 (factory method pattern)
객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴
상속 관계에 있는 두 클래스에서 상위 클래스가 중요한 뼈대를 결정하고, 하위 클래스에서 객체 생서에 관한 구체적인 내용을 결정하는 패턴
여러 종류의 객체를 생성하려고 할 때 인터페이스를 통해 하나로 관리
스프링의 DI는 팩토리 메서드 패턴을 사용한다. BeanFactory를 상속받은 ApplicationContext에서 getBean() 팩토리 메소드를 통해 bean을 주입받을 수 있다.
2-3. 프록시 패턴 (proxy pattern)
대상 객체(subject)에 접근하기 전 그 접근에 대한 흐름을 가로채 대상 객체 앞단의 인터페이스 역할을 하는 디자인 패턴
Spring AOP(Aspect-Oriented Programming)에서 프록시 패턴이 사용된다.
프록시 객체를 통해 실제 객체에 접근하고, 메서드 호출 전후로 부가 기능(트랜잭션, 로깅 등)을 삽입한다.
예를 들면, @Transactional을 사용하면 트랜잭션 프록시가 생성되어 메서드 실행 전후로 트랜잭션 관리가 수행된다.
2-4. 템플릿 메소드 패턴 (template method pattern)
'템플릿 메서드 패턴'은 상위 클래스에서 기본적인 로직을 정의하고, 하위 클래스가 세부 사항을 구현하도록 하는 패턴이다.
Spring은 JdbcTemplate, RestTemplate, JpaTemplate 같은 템플릿 클래스를 제공한다.
3. 정리
Singleton Pattern | Factory Method Pattern | Proxy Pattern | Template Method Pattern | |
Spring 사용 예시 | Spring Bean | DI | AOP (Transaction, Logging) | JdbcTemplate, RestTemplate |
그 외에도 다양한 디자인 패턴을 사용하고 있을 것이지만, 대표적으로 위의 4가지 디자인 패턴을 사용하고 있다.
상황에 맞게 적절한 디자인 패턴을 활용하는 연습이 필요할 것 같다.
'java & spring' 카테고리의 다른 글
[Spring Security] csrf().disable()하는 이유는?! 그리고 CORS (3) | 2024.11.03 |
---|---|
[Spring] 싱글톤 레지스트리와 스프링의 IoC 컨테이너 (0) | 2024.08.20 |
[Spring] IoC 컨테이너와 Bean (0) | 2024.08.13 |
[Java/Spring] Java Bean vs Spring Bean, Bean이란? (0) | 2024.08.08 |