해당 게시물은 인프런 - "스프링 핵심 원리 - 기본편" 강의를 참고하여 작성한 글 입니다
유료강의이므로 자세한 내용은 없고, 간단한 설명 위주로 정리했습니다 강의 링크

빈 스코프

스프링 빈의 다양한 스코프

  • 싱글톤
  • 프로토타입
  • 웹 관련 스코프
    - request
    • session
    • application

프로토타입 스코프

프로토타입 스코프를 스프링 컨테이너에 조회하면 스프링 컨테이너는 항상 새로운 인스턴스를 생성해서 반환한다
스프링 컨테이너는 프로토타입 빈을 생성하고, 의존관계 주입, 초기화까지만 처리한다
프로토타입 빈을 관리할 책임은 클라이언트에 있어서 종료 메소드가 호출되지 않는다

프로토타입 스코프 - 싱글톤 빈과 함께 사용시 문제점

싱글톤 빈에서 프로토타입 빈 사용

다음은 clientBean이라는 싱글톤 빈이 의존관계 주입을 통해서 프로토타입 빈을 주입 받는 예다

clientBean이 내부에 가지고 있는 프로토타입 빈은 이미 과거에 주입이 끝난 빈이다
따라서 사용할 때마다 새로 생성되지 않는다

프로토타입 스코프 - 싱글톤 빈과 함께 사용시 Provider로 해결

싱글톤 빈과 프로토타입 빈을 함께 사용할 때, 항상 새로운 프로토타입 빈을 생성할 수 있는 방법이 있다

ObjectProvider

ObjectProvider를 사용하면 DL(Dependency Lookup)을 쉽게 할 수 있다

@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanProvider;

public int logic() {
     PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
     prototypeBean.addCount();
     int count = prototypeBean.getCount();
     return count;
}

prototypeBeanProvider.getObject()를 통해서 항상 새로운 프로토타입 빈이 생성된다
objectProvidergetObject()를 호출하면 내부에서는 스프링 컨테이너를 통해 해당 빈을 찾아서 반환한다

웹 스코프

웹 스코프의 특징은 다음과 같다

  • 웹 환경에서만 동작한다
  • 프로토타입과 다르게 스프링이 웹 스코프의 종료시점까지 관리한다
  • 따라서 종료 메소드가 호출된다

웹 스코프의 종류는 다음과 같다

  • request: HTTP 요청 하나가 들어오고 나갈 때까지 유지하는 스코프, 각각의 HTTP 요청마다 별도의 빈 인스턴스가 생성되고 관리된다
  • session: HTTP Session과 동일한 생명주기를 가지는 스코프다
  • application: 서블릿 컨텍스트(Servlet Context)와 동일한 생명주기를 가지는 스코프
  • websocket: 웹 소켓과 동일한 생명주기를 가지는 스코프다

request 스코프 예제

동시에 여러 HTTP 요청이 오면 어떤 요청이 남긴 로그인지 정확히 구분하기 어렵다
이럴때 사용하기 좋은것이 request 스코프다

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {

    private String uuid;
    private String requestURL;

    public void setRequestURL(String requestURL) {
        this.requestURL = requestURL;
    }

    public void log(String message) {
        System.out.println("[" + uuid + "]" + "[" + requestURL + "] " + message);
    }

    @PostConstruct
    public void init() {
        uuid = UUID.randomUUID().toString();
        System.out.println("[" + uuid + "] request scope bean create: " + this);
    }

    @PreDestroy
    public void close() {
        System.out.println("[" + uuid + "] request scope bean close: " + this);
    }
}

@Scope(value= "request")를 통해 request 스코프로 지정한다
@PostConstruct 초기화 메소드로 빈이 생성되는 시점에 uuid를 생성해 저장한다
uuid를 지정하면 다른 HTTP 요청과 구분할 수 있다
proxyMode = ScopedProxyMode.TARGET_CLASS를 통해 MyLogger 클래스의 가짜 프록시 클래스를 미리 만들어서 다른 빈에 주입할 수 있다
스프링 애플리케이션을 실행하는 시점에서 request 스코프 빈은 아직 생성되지 않고, 실제 고객의 요청이 와야 생성이 된다.
그래서 프록시로 미리 빈을 만들어서 주입을 해야 한다

웹 스코프와 프록시 동작 원리

프록시 객체는 요청이 오면 그때 내부에서 진짜 빈을 요청하는 위임 로직이 들어있다

프록시 객체 내부에 myLogger를 찾는 방법을 알고 있다
클라이언트가 myLogger.log()를 호출하면, 사실은 프록시 객체의 메소드를 호출한다
그러면 프록시 객체는 request 스코프의 진짜 myLogger.log()를 호출한다

0개의 댓글

Powered by GraphCDN, the GraphQL CDN