3.4.3. The other scopes
2.0에 새로 추가 된 Bean의 Scope들로 request, session, global session이 있습니다. 그리고 이 Scope들은 웹에서 사용하도록 만들어진 것이기 때문에 web-based applicationContext에서만 사용할 수 있습니다. 안그러면 IllegalStateException 이게 발생합니다.
WebApplicationContext 인터페이스를 구현한 클래스들로 다음과 같습니다.
- AbstractRefreshablePortletApplicationContext, AbstractRefreshableWebApplicationContext, GenericWebApplicationContext, StaticPortletApplicationContext, StaticWebApplicationContext, XmlPortletApplicationContext, XmlWebApplicationContext
물론 위에서 abstract와 generic(여러 확장 포인트를 제공하기 위해 만든 클래스들)과 static(테스트 용도로 만들어둔 클래스들)을 제외 하면 사실상 XmlPortletApplicationContext, XmlWebApplicationContext 이 두 개가 남습니다.
3.4.3.1. Initial web configuration
새로 추가된 웹 어플리케이션을 위한 scope들을 사용하려면 web.xml에 리스너 or 필터를 등록해야 합니다.
Sevlet 2.4 이상의 버젼을 사용할 때는 아래 처럼 리스너를 등록합니다.
...
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
...
</web-app>
Servlet 2.4 미만의 버젼을 사용할 때는 아래 처럼 필터를 등록합니다.
..
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
3.4.3.2. The request scope
매 요청 마다 해당 객체를 사용할 수 있으며 각각의 요청은 서로 다른 객체를 가지게 됩니다. 그리고 요청에 대한 처리가 끝나면(컨트롤러에서 해당 메소드가 종료 되면) 더 이상 사용할 수 없습니다.
3.4.3.3. The session scope
매 세션 마다 해당 객체를 사용할 수 있으며 각각의 세션은 서로 다른 객체를 가지게 됩니다. 그리고 세션이 닫히면(브라우저를 끄거나 타임오버가 되면) 더 이상 사용할 수 없습니다.
3.4.3.4. The global session scope
위에서 설명한 session Scope과 동일하며 단지 포틀릿 어플리케이션에서만 사용할 수 있다는 차이가 있습니다. 포틀릿 어플리케이션이 뭔지 모르기 때문에 pass..
3.4.3.5. Scoped beans as dependencies
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<!-- a HTTP Session-scoped bean exposed as a proxy -->
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
<!-- this next element effects the proxying of the surrounding bean -->
<aop:scoped-proxy/>
</bean>
<!-- a singleton-scoped bean injected with a proxy to the above bean -->
<bean id="userService" class="com.foo.SimpleUserService">
<!-- a reference to the proxied 'userPreferences' bean -->
<property name="userPreferences" ref="userPreferences"/>
</bean>
</beans>
위와 같이 <aop:scoped-proxy/>를 항상 request, session, globalsession 빈을 만들 때 넣어줘야 합니다.
보통은 아래 처럼 DI하는 것을 생각할 수 있습니다.
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
하지만 이때 userPreferences 빈은 scope이 session이지만 userManager의 scope이 singletone(default가 singleton이죠.)이기 때문에 문제가 발생합니다. 매 세션 마다 새로운 객체를 만들어 줘야 하지만 저 세션 객체를 사용하는 빈의 생성을 한 번 밖에 안하기 때문에 원하던 대로 동작하지 못합니다.
따라서 매 세션 마다 새로운 객체를 만들어서 줄 프록시를 만들기 위해서 <aop:scoped-proxy/>를 사용합니다.
3.4.3.5.1. Choosing the type of proxy created
<bean id="userPreferences" class="com.foo.DefaultUserPreferences" scope="session">
<aop:scoped-proxy proxy-target-class="false"/>
</bean>
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
Spring AOP는 프록시 기반이며 프록시를 만들 때 인터페이스를 기반으로 만들 거라면 JDK의 API를 사용하고 클래스 기반으로 만들 때에는 CGLib을 사용합니다.
위에서도 Spring AOP를 사용하고 있고 기본적으로 CGLib을 사용하여 프록시를 만들도록 설정되어 있습니다.
대상이 되는 객체가 어떤 인터페이스를 기반으로 만들어 졌고 JDK의 프록시 API를 사용하고 싶다면 위의 예제 코드 처럼 proxy-target-class 속성의 값에 false 를 넣어 주면 됩니다.