끄적끄적 코딩일지

[Spring 기초] Scope 사용하기 본문

Spring

[Spring 기초] Scope 사용하기

BaekGyuHyeon 2022. 6. 7. 09:57

Spring에서 등록되는 Bean은 기본적으로 싱글톤 패턴으로 관리를 한다. 때문에 어디에서든 똑같은 Bean을 호출하면 하나의 인스턴스를 조회할 수 있다. 하지만 용도에 따라서 요청할때마다 다른 인스턴스가 필요하게 될때도 있다. 이를 위해서 Spring에서는 Scope를 지원한다.

 

Scope에 들어가기 앞서 싱글톤 패턴과 프로토타입 패턴에 대해 짚어보고 들어가도록 하자


싱글톤 패턴(Singleton pattern) 이란?

어플리케이션이 시작할때 특정 class에 최초 한번만 메모리를 할당하고 해당 메모리 안에서 인스턴스(객체)를 만들어서 사용하는 방법이다.

때문에 어디에서든 항상 동일한 인스턴스를 조회할 수 있다. 

 

싱글톤 패턴의 장점

  • 인스턴스가 단 한번 생성되기 때문에 메모리 낭비를 줄일 수 있다.
  • 전역 class이므로 다른 인스턴스간의 데이터 공유가 가능하다.
  • 인스턴스가 절대적으로 한개만 존재하는 것을 보증하기에 개발 시 실수를 줄일 수 있다.
  • 싱글톤 객체를 사용하지 않고는 인스턴스를 생성할 수 없다.

싱글톤 패턴의 단점

  • 전역변수보다 사용하기가 불편하다
  • 싱글톤 인스턴스가 혼자 너무 많은 일을 하거나 공유시키면 결합도가 높아진다.
  • 멀티 쓰레드를 사용할때 동기화 처리를 하지 않으면 여러개의 인스턴스가 생성될 수 있다.
  • 객체의 파괴 시점을 컨트롤하기 어려울 수 있다.

Spring에서의 IoC를 이용하면 이러한 싱글톤 방식의 단점을 보완할 수 있다.


프로토타입 패턴(Prototype Pattern) 이란?

어플리케이션이 실행될때 객체를 미리 만들어 두고 필요할때마다 해당 객체의 복사본(clone)을 제공하는 방식이다.

미리 해당 객체를 생성하는데 필요한 과정이 포함되어있어 편하게 생성하는데 복잡한 객체를 관리하는데 좋은 방법이다.

 

프로토타입 패턴의 장점

  • 구현클래스에 의존하지 않고 객체를 복사할 수 있다.
  • 프로토타입이 미리 정의되어 있어 초기화 코드를 제거할 수 있다.
  • 복잡한 오브젝트를 편리하게 만들수 있다.

프로토타입 패턴의 단점

  • 순환참조가 있는 복잡한 객체를 복제하는것은 까다로울 수 있다.

Scope를 사용한 Bean 관리

Spring 에서 bean을 등록하면 기본적으로 싱글톤 패턴을 사용하여 객체를 관리한다. 즉 요청이 있을때마다 항상 똑같은 객체를 반환해준다. 하지만 Scope를 사용하면 해당 객체를 프로토타입 패턴으로 관리할 수 있다. 

 

@Scope("prototype")
public class PrototypeClass{
    private int count = 0;
    public int addCount(){
        return ++count;
    }
}

@Controller
public class TestController{
    @Autowired
    private ObjectProvider<PrototypeClass> prototypeProvider;
    
    @GetMapping("/")
    public int addCount(){
        PrototytpeClass proto = prototypeProvider.getObject();
        return proto.addCount();
    }
}

 


ObjectProvider를 쓰는 이유

Controller와 같이 싱글톤 객체에서 프로토타입 객체를 의존하는 경우에는 프로토타입 객체가 제대로 동작하지 않는다. 해당 프로토타입 객체를 의존하고 있는 객체가 싱글톤으로 관리되기 때문에 해당 싱글톤 객체가 의존하고 있는 객체들도 new 같은 객체의 생성을 선언하지 않는이상 기본적으로 싱글톤처럼 관리된다. 때문에 Prototype객체를 제대로 사용하기 위해서는 필요할때마다 DI Contatiner에서 해당 객체를 가져오도록 해야한다.


Proxy를 사용한 방법

꼭 ObjectProvider을 사용하지 않아도 Scope 어노테이션만 수정함으로써 ObjectProvider처럼 쓰는 방법도 있다.

@Scope(value="prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)
public class PrototypeClass{
    private int count = 0;
    public int addCount(){
        return ++count;
    }
}

위처럼 Scope 어노테이션 안에 proxyMode 를 설정하면 싱글톤 패턴처럼 써도 prototype처럼 동작한다. 그 이유는 Spring이 먼저 의존성 주입을 할때 가짜 proxy객체를 먼저 주입하고, 해당 proxy객체에 접근할때마다 prototype객체를 생성하여 제공해준다.

 

즉, 해당 객체를 꼭 필요한 시점까지 지연처리 할 수 있다.