Singleton Pattern

2023, Mar 04    
  • 어플리케이션 당 존재하는 객체의 인스턴스를 오직 한개만 보장하는 매커니즘으로 클래스 인스턴스를 하나만 만들고, 그 인스턴스로의 전역 접근을 제공한다.
  • 이 패턴은 공유 리소스를 관리할 때와 로깅과 같은 cross-cutting서비스를 제공할 때 유용하다.

1. usage

  • 하나만 존재해도 잘 돌아가는 객체들을 대상으로 적용하는 패턴으로 인스턴스가 2개 이상이 되면 리소스를 잡아먹는다거나 결과에 일관성이 없다는 등의 문제가 생길 수 있다.
  • 전역변수와의 차이점 : 전역변수는 어플리케이션이 시작될 때 객체가 생성되게 되는데 사용전에 이미 자원을 차지하게 되어 불필요한 객체 생성이 될 수 있다.
  • 단점
    • 클래스 로더가 여러개라면 싱글턴 사용시, 클래스 로더를 직접 지정해서 여러번 로딩되지 않도록 해야한다.
    • 리플렉션, 직렬화, 역직렬호하도 싱글턴에서 문제가 된다.

2. singleton beans

  • 일반적으로 싱글톤은 어플리케이션에 전역에 유일한 것이다. 하지만 스프링은 아니다. 이러한 제약은 느슨해졌고 대신에 스프링은 application이 아닌 spring Ioc 컨테이너당 객체 한개로 싱글톤을 규정하고 있다.
  • 이 뜻은 스프링은 application context당 오직 한개의 bean만 생성한다
  • 어플리케이션에는 여러개의 Spring 컨테이너를 존재할 수 있기 때문에 Spring의 접근 방식은 싱글톤의 엄격한 정의와 다르다.
  • 따라서 컨테이너가 여러 개인 경우, 동일한 클래스의 여러 객체가 단일 애플리케이션에 존재할 수 있다.
  • 디폴트는 Spring은 모든 bean들을 싱글톤으로 생성한다.
    • @Scope 어노테이션을 사용해서 빈 스코프를 변경할 수 있다.

2. Autowired Singletons

예를 들어서, 한개의 어플리케이션 context에 두개의 controller를 생성하고 각각 같은 타입으로 빈을 주입한다고 하면, 콘솔에 찍어봤을때 같은 object Id를 반환하는 것을 알 수 있다.

@RestController
@RequiredArgsConstructor
@RequestMapping("expiredSessions")
public class ExpiredSessionResource {
    private final ExpiredSessionFlowService expiredSessionFlowService;

    @PutMapping
    public void expiredSession() {
        System.out.println(expiredSessionFlowService);
    }
}

여러번 호출해서 찍어보면 ExpiredSessionFlowService@41d2528f 으로 동일하게 출력되는 것을 알 수 있다.

09:20:52.579 TRACE [3c8343fc9684497a,3c8343fc9684497a] [050-exec-1] o.h.type.descriptor.sql.BasicBinder     : 64 bind            binding parameter [1] as [BIGINT] - [1675210852345]
spectra.attic.talk.crema.thirdparty.kakao.kakao.service.flow.ExpiredSessionFlowService@41d2528f

09:20:59.570 TRACE [447f5b5ee5bdf2fe,447f5b5ee5bdf2fe] [050-exec-2] o.h.type.descriptor.sql.BasicBinder     : 64 bind            binding parameter [1] as [BIGINT] - [1675210859549]
spectra.attic.talk.crema.thirdparty.kakao.kakao.service.flow.ExpiredSessionFlowService@41d2528f