原文轉自:https://blog.csdn.net/qq_36951116/article/details/79121887
先了解一下request和session這兩個作用域是幹嘛的
以下是官方文檔中文翻譯:
請求作用域
考慮如下的bean定義:
<bean id="loginAction" class="com.foo.LoginAction" scope="request"/>
對於每個http請求,Spring容器會創建一個 LoginAction
bean 的新實例。也就是說,loginAction
bean 的作用域限於 HTTP 請求範圍。 你可以在請求內隨意修改這個bean實例的狀態,因爲其他 loginAction
bean實例看不到這些變化,bean實例是與特定的請求相關的。 當請求處理完畢,對應的bean實例也就銷燬(被回收)了。
考慮如下的bean定義:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
在每個HTTP Session
的生命週期內,Spring容器會根據id爲 userPreferences
的bean定義創建一個 UserPreferences
bean 的新實例。 也就是說,userPreferences
bean 的作用域限於 HTTP Session
範圍。和請求作用域 request-scoped
bean 類似, 因爲每個會話域 session-scoped
bean的範圍限於特定的 HTTP Session
內部,所以一個 Session
內的 userPreferences
bean也是可以被隨意修改, 而不會影響到其他 Session
中的 userPreferences
bean。當一個HTTP Session
最終用完被JVM回收時,相關的會話域 session-scoped
bean也被一起回收。
上面都是spring官方文檔講的關於request和session的作用
這裏就不講使用request session這些作用域要在web.xml中做什麼了,這些對於使用spring mvc的我來說沒什麼用。
下面講講當作用域設置爲這兩個時,注入到其他bean中怎麼使用,以及爲什麼可以這樣用。
怎麼使用?
爲什麼加<aop:scoped-proxy/>標籤就可以了呢?
將上述作用域的bean作爲依賴
Spring IoC 容器不僅負責管理對象(beans)的創建,也負責有合作(依賴)關係對象之間的組裝。 如果你想將一個HTTP 請求作用域的bean注入到另一個 bean,必須注入一個 AOP 代理來取代請求作用域的bean本身。 也就是說,你得有一個和作用域bean實現了相同接口、能在相應作用域(例如,HTTP 請求) 訪問真正的請求域bean目標對象的代理對象,而且這個代理對象要能把方法調用委派給真正的請求域bean, 然後把代理對象注入到請求域bean該注入的地方。
對於作用域爲 |
下述代碼雖然只有一行,但讀者不僅要“知其然”,更要“知其所以然”。
<?xml version="1.0" encoding="UTF-8"?> <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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 將一個HTTP Session bean 暴露爲一個代理bean --> <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"> <!-- 通知Spring容器去代理這個bean --> <aop:scoped-proxy/> </bean> <!-- 將上述bean 的代理注入到一個單例bean --> <bean id="userService" class="com.foo.SimpleUserService"> <!-- 引用被代理的 userPreferences bean --> <property name="userPreferences" ref="userPreferences"/> </bean> </beans>
爲了創建上文提到的代理對象,要在 request
請求、 session
會話、 globalSession
全局會話 和自定義作用域的bean聲明中加入 <aop:scoped‐proxy/>
子元素。 (參考 the section called “選擇要創建的代理類型” 和 Chapter 33, XML Schema-based configuration) 。爲什麼要這麼做呢?讓我們將這幾個作用域的bean定義與單例作用域的bean定義做個對比。 (下列代碼的 userPreferences
bean定義實際是 不完整的 )。
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/> <bean id="userManager" class="com.foo.UserManager"> <property name="userPreferences" ref="userPreferences"/> </bean>
在上述例子中,將HTTP Session
會話域的 userPreferences
bean 注入進了單例域 userManager
。 代碼的關鍵在於userManager 是個單例bean,它在每個Spring 容器中只會被初始化 一次, 它的依賴對象(在這個例子中是 userPreferences
bean)也只會被注入一次。這就意味着 userManager
每次操作的都是在最開始注入進來的同一個 userPreferences
對象。
當你把一個生命週期較短的bean注入至一個生命週期較長的bean時,例如把HTTP Session
bean注入到單例bean, 這種情況肯定 不是 你所期望的。相反,你希望有個唯一的 userManager
單例對象,在每個HTTP Session
的生命週期內, 都能有一個專門的 userPreferences
對象供 userManager
使用。因此,Spring容器會創建一個代理類, 使之與 UserPreferences
類實現相同的接口(理論上也是一個 UserPreferences
對象),並能根據作用域(HTTP 請求、 Session
,等等)去獲得真正的 UserPreferences
對象。 Spring容器將這個代理類的對象注入到 userManager
, 但是 userManager
並不清楚它獲得的 UserPreferences
其實是個代理。 在這個例子中,當UserManager 實例調用注入的 UserPreferences
對象的某個方法時,實際上調用的是代理對象的方法。 然後,代理對象從HTTP Session
中獲取、並將方法調用委派給真正的 UserPreferences
對象。
所以,當你需要將 request-
, session-
, and globalSession-scoped
作用域的 bean 注入至其他合作者bean的時候,要按照下面的方法去正確地配置。
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"> <aop:scoped-proxy/> </bean> <bean id="userManager" class="com.foo.UserManager"> <property name="userPreferences" ref="userPreferences"/> </bean>