top bar

글 목록

2017년 12월 14일 목요일

[Spring] Request Bean Scope

스프링에서의 Bean이 기본적으로 'Singleton'이라는 것은 누구나 안다. 하지만 Singleton으로 관리되는 Bean의 Lifecycle을 'Scope'어노테이션을 이용해 제어 할 수 있다. 스프링의 Bean Scope는 총 5가지 인데, singleton, prototype, request, session, global session이 그것이다.

이 중에서, 조금은 특이한 방법으로 관리되는 request scope의 bean에 대해서 살펴 보고자 한다.

가령, 아래와 같은 HelloMessageGenerator 라는 클래스가 있다고 하자.

class HelloMessageGenerator {
    public String getMessage() {
        return "Hello " + this;
    }
}

HelloMessageGenerator의 getMessage메소드를 통해서 문자열을 가져오는데, 자바에서 유일하게 오버로딩 된 '+' 연산자를 통해서 'Hello [참조값]' 이라는 문자열을 반환한다. 이를 통해 getMessage를 호출하는데 사용되는 인스턴스의 참조값을 알 수 있다.

그리고 아래처럼 Spring Configuration에, 해당 클래스의 Bean 설정 코드를 작성한다.

@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator requestMessage() {
    return new HelloMessageGenerator();
}

HelloMessageGenerator의 빈 설정을 보면 Scope어노테이션에 'proxyMode' 라는 것이 눈에 띈다. Aop를 적용하려는 것도 아닌데 왜 proxyMode를 설정해야 할까?

'request scope' 라는 것은 말그대로 Bean의 lifecycle이 request와 같다는 것이다. 때문에 해당 Bean은 '요청 -> 응답'이 끝나면 제거 되며, 요청이 없으면 생성되지 않는다. reuqest scope의 이러한 속성 때문에 proxy를 설정해야 하는데, 이유는 이렇다. 

일단 아래처럼 Controller를 작성해 보자.

@Controller
public class ScopesController {
    @Resource(name = "requestMessage")
    HelloMessageGenerator requestMessage;
 
    @RequestMapping("/scopes")
    public String getScopes(Model model) {
        requestMessage.setMessage("Good morning!");
        model.addAttribute("requestMessage", requestMessage.getMessage());
        return "scopesExample";
    }
}

서블릿 컨테이너에 스프링 기반의 웹 어플리케이션이 로딩될때 (쉽게 말해 톰캣을 구동할때) 각 빈이 생성되고 빈 컨테이너에 등록되며 'Dependency Injection'이 일어난다. 한마디로 이 시점에 각 객체의 의존관계를 바탕으로 빈이 주입 된다는 것이다. 위 경우는 ScopesController에 HelloMessageGenerator의 인스턴스가 주입되어야 한다. 하지만 해당 빈은 request scope이기때문에 생성할 수 없다. 때문에 'proxy'를 임시적으로 생성하여 의존성 주입을 수행하는 것이다. 그 후에 진짜 요청이 들어오면 다시 초기화를 하여 빈을 사용하게 된다.

proxy는 일단 그렇고, 결과적으로 위 코드를 수행하면 view단에 찍히는 'requestMessage' 문자열이 요청 때마다 다른 값으로 노출 될 것이다. 참고로 session, global session scope 설정 시에도 proxyMode를 지정해 줘야 하는데, 원리는 request scope의 경우와 같다.

정리 끗.

참고 - http://www.baeldung.com/spring-bean-scopes