Spring 3.2.12 + Struts 2.3.20。Action 類配置:
@Component
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) // 顯式聲明單例
@ParentPackage("struts-default")
@Namespace("/test")
public class TestAction { ... }
運行發現:Spring 容器中持有單例 TestAction,但 Struts 每次請求都獲得新實例 (日誌輸出 `this` 和 `spring` 獲取的 bean 內存地址不同)。
Struts2-Spring 插件的工作機制:
Struts2 Action 必須是多例 (prototype),因為 Action 實例持有請求狀態 (參數、驗證錯誤等),單例會導致併發數據污染。
<package name="test" namespace="/test" extends="struts-default">
<action name="testAction" class="com.me.permission.action.TestAction">
<result name="success">/index.jsp</result>
</action>
</package>
或使用約定插件 (需 `struts2-convention-plugin`):
@Action(value = "testAction", results = { @Result(name = "success", location = "/index.jsp") })
public String test() { ... }
// 類上無 Spring 註解
public class TestAction {
@Autowired // 或提供 setter
private UserService userService; // Service 為單例
private String param; // 請求參數,每次請求新實例隔離
public String test() { ... }
}
Struts2 的 `SpringObjectFactory` 邏輯:
// 簡化邏輯
public Object getBean(String beanName) {
if (applicationContext.containsBean(beanName)) {
return applicationContext.getBean(beanName); // 返回 Spring 管理的 bean
} else {
// 容器無此 bean 定義 → 按 prototype 模式自動實例化類 (需類在掃描路徑)
return instantiateClass(beanName);
}
}
| 組件類型 | Spring Scope | Struts2 管理 | 說明 |
|---|---|---|---|
| Action | **不由 Spring 管理** (或 prototype) | 是 | 每請求一實例,持有請求狀態 |
| Service | Singleton | 否 | 無狀態業務邏輯,線程安全 |
| Dao/Repository | Singleton | 否 | 無狀態數據訪問 |
| Controller (Spring MVC) | Singleton | N/A | Spring MVC Controller 設計為單例,參數通過方法傳遞 |
在 Action 中打印 `this.hashCode()` 或注入 `ApplicationContext` 獲取 bean 對比,連續請求觀察是否同一實例。