싱글톤 패턴
싱글톤 패턴이란 객체 지향 프로그래밍에서 클래스의 인스턴스가 단 하나만 생성되도록 보장하는 디자인 패턴이다.
여러 사용자가 동시에 접근해서 한 인스턴스를 쓸 때 싱글톤 패턴을 사용하면 메모리 낭비를 방지하며 접근이 용이한 장점이 있다.
하지만 "전역 상태" 이기 때문에 테스트가 어렵고 SRP, DIP 원칙을 위배하는 단점이 있어 안티패턴이라고도 불린다.
이러한 안티패턴에 가까운 싱글톤 패턴을 왜 스프링은 적용했을까? 스프링은 대규모 시스템에서 효율적인 자원관리가 필수적이기 때문에
적용했다.
스프링은 스프링 컨테이너에서 각 빈(Bean)의 인스턴스 하나만 생성하고 관리하는 싱글톤 패턴을 적용했다. 이 과정에서 의존성 주입 (Dependency Injection)을 활용했고 싱글톤 패턴의 문제점과 주의점을 해결했다.
하지만 이럼에도 불구하고 싱글톤 인스턴스에 공유되는 변수를 만들면 안된다는 주의점은 여전히 존재하기 때문에 신경써줘야 한다.
팩토리 메서드 패턴
팩토리 메서드 패턴은 객체의 생성 과정을 하위 클래스에 위임함으로써 객체 생성을 캡슐화하는 디자인 패턴이다. 이 패턴은 객체 생성의 책임을 특정 클래스가 아닌 여러 "팩토리" 클래스에 분산시킴으로써 코드의 유연성을 높이고 확장성을 강화한다. 이는 SOLID 원칙 중 SRP(단일 책임 원칙)과 OCP(개방-폐쇄 원칙)을 준수할 수 있게 돕는다. 각 객체의 생성 로직이 개별 팩토리 내에 캡슐화되어 있기 때문에 새로운 타입의 객체를 추가하거나 변경해야 할 때 기존 코드를 수정하지 않고도 확장이 가능하다는 장점이 있다.
스프링 프레임워크에서는 어떻게 팩토리 메서드 패턴을 사용할까? 스프링은 FactoryBean, BeanFactory와 같은 인터페이스를 통해 광범위하게 적용되어 있다. FactoryBean은 스프링 빈을생성하고 구성하는 과정을 캡슐화한 것이다. 반면 BeanFactory는 스프링 빈의 생성과 관리를 담당하는 가장 기본적인 컨테이너 역할을 수행한다.
하지만 팩토리 메서드 패턴의 적용으로 각 제품 구현체에 대한 팩토리 객체를 모두 구현해야 한다는 단점도 존재한다. 이는 클래스의 개수가 많아져 관리가 복잡해질 수 있으며 특히 크고 복잡한 애플리케이션에서는 이 문제가 더욱 두드러질 수 있습니다. 그럼에도 불구하고 이 패턴은 애플리케이션의 확장성과 유지 보수성을 크게 향상시킬 수 있는 강력한 방법으로 스프링 프레임워크 내에서 중요한 역할을 한다.
프록시 패턴
프록시 패턴은 스프링 프레임워크의 핵심 기능 중 하나인 AOP(Aspect-Oriented Programming) 구현에 핵심적으로 사용되는 디자인 패턴이다. 이 패턴은 대상 객체의 기능을 확장하거나 제어할 수 있도록 대리 객체(프록시)를 통해 대상 객체에 대한 접근을 관리한다. 프록시 패턴의 사용은 보안 강화, 캐싱, 로깅, 모니터링과 같은 다양한 장점을 제공하며 특히, 스프링에서는 AOP를 통해 애플리케이션 전반에 걸친 공통 기능의 재사용성을 높이고 코드의 결합도를 낮추는 데 큰 역할을 한다.
스프링 프레임워크 내에서 프록시 패턴은 주로 두 가지 방식으로 활용된다. 첫째, Bean의 프록시화를 통해 스프링은 Bean들을 동적 프록시 기법을 사용하여 프록시 객체로 생성한다. 이 과정에서 @Transactional과 같은 어노테이션 처리가 이루어지며, 스프링은 이를 통해 트랜잭션 관리와 같은 공통 기능을 효과적으로 적용할 수 있. 둘째, 스프링은 대상 객체가 인터페이스를 구현하고 있을 경우 JDK 동적 프록시를 사용하고, 그렇지 않은 경우 CGLIB 라이브러리를 사용하여 프록시 객체를 생성한다. 이를 통해 인터페이스의 유무와 상관없이 일관된 방식으로 객체의 프록시화를 지원한다.
그러나 프록시 패턴의 사용은 구현 복잡도 증가와 처리 시간 지연과 같은 단점을 가지고 있다. 특히, 모든 요청이 프록시를 거쳐야 하기 때문에 성능 저하가 발생할 수 있으며, 프록시 객체를 만들고 관리해야 하는 부담도 존재한다. 그래서 스프링은 프록시 패턴의 사용을 최적화하고, 필요한 경우에만 적절히 적용하여 이러한 단점을 최소화했다.