이 중에서, 조금은 특이한 방법으로 관리되는 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