struts2與struts2-spring-plugin的整合

原文名稱:使用 struts2 builder alias 機制加載objectFactory

以下代碼基於 struts2 版本2.1.8.1 版本分析。

在使用 Struts2的過程中,我們都喜歡使用 struts2 的spring 插件來讓 spring 作爲struts2 的默認對象容器,原理就在於在加載 struts2 之前先加載 spring容器,然後將 spring 容器加載至 applicationContext中,在 struts2 的objectFactory (稱之爲對象容器)實現中,找到 spring 容器並進行各項對象創建工作。


 spring插件中,使用了 StrutsSpringObjectFactory 類來作爲struts2 的對象容器,實現過程即除重寫 objectFactory 的各項buildBean 方法以符合 spring 規範之外,其它則就是根據 struts2 的各項參數設置 spring參數(如 autoType 等)。之所以使用此類作爲 struts2 的對象容器,原因就在於在 struts2-spring.jar 中的struts-plugin.xml 中定義瞭如下的聲明:

<bean type="com.opensymphony.xwork2.ObjectFactory" name="spring" class="org.apache.struts2.spring.StrutsSpringObjectFactory" />

<constant name="struts.objectFactory" value="spring" />

第一句是聲明瞭一個實現類 objectFactory 的對象,這就是 spring插件所提供的對象容器,而第二句則聲明屬性 struts.objectFactory 的值爲spring ,即 key spring 的對象將成爲 struts2的對象容器。


爲什麼這樣說,我們可以看一下 struts2 對struts.objectFactory 的解釋,以下解釋摘自 struts2 中的default.properties:


### if specified, the default object factory can be overridden here

### Note: short-hand notation is supported in some cases, such as "spring"

###       Alternatively, you can provide a com.opensymphony.xwork2.ObjectFactory subclass name here


即只要設置了此值,則默認的對象容器,將被改寫,那麼 spring 插件所提供的功能就是定義了一個 spring 實現的對象容器,並且重寫了 struts2 定義,將spring 容器再成爲 struts2 的對象容器。

再反過來,我們可以看到 struts-default.xml 中也定義瞭如下的容器聲明:


<bean class="com.opensymphony.xwork2.ObjectFactory" name="xwork" />

<bean type="com.opensymphony.xwork2.ObjectFactory" name="struts" class="org.apache.struts2.impl.StrutsObjectFactory" />


這裏定義了兩個 objectFactory 實現,一個爲原生 xwork中的 objectFactory ,另一個則爲 struts所提供的 strutsObjectFactory 。其中xwork  key xwork ,而struts  key struts 。


我們知道,在 struts2( 實際上就是 xwork),所確定最終的 objectFactory 的實現體是需要找一個類型爲 ObjectFactory ,key 值爲 default的實現類,而這 2 個xml 定義中都沒有提到 default 這個key 值,那麼就是在程序內部所實現了的。


首先看, struts2 是如何尋找 objectFactory實現的,類 DefaultConfiguration 中第181 行至 186行,如何上就是如何創建整個 struts2 容器,並確定對象容器的過程。如下代碼所示:


// Set the bootstrap container for the purposes of factory creation

Container bootstrap = createBootstrapContainer();

setContext(bootstrap);

container = builder.create(false);

setContext(container);

objectFactory = container.getInstance(ObjectFactory.class);


上文中的 builder.create(false) 即是創建容器的過程,而 container.getInstance(ObjectFactory.class) 則是取得(創建)對象容器的過程。那麼實際上,在 builder.create(false) 過程中,實際的對象容器已經確定了,即 key 爲default, 類型爲 ObjectFactory的類已經注入到容器中了。那麼這個信息是如何注入的呢,這就歸結於 builder (即ContainerBuilder )所提供的 alias 機制了。


什麼叫 alias?熟悉 spring 的就知道,其實就是一個別名嘛,我們可以將一個 id 的aaBean 的對象定義一個別名叫 bbBean ,那麼在struts2 中,我們也可以將 key 爲spring 的對象,定義一個別名叫 default !


這就是程序內部實現的原理了,就是找到屬性名爲 struts.objectFactory 的屬性值,然後將此屬性值定義一個別名爲 default ,此後就將此對象作爲 Struts2容器最終找到的對象了。


那麼終需要一個對象來調用 builder 的alias 方法吧,此類就是 BeanSelectionProvider ,在初始化 struts2容器時,此類被作爲 containerProvider 提供給containerBuilder ,那麼在後面肯定會用到此類了。其實就是在初始化之前提供各項信息給 builder ,那麼它提供的信息是哪些呢,在方法 public void register(ContainerBuilder builder, LocatableProperties props) 中實現 如下:

alias(ObjectFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY, builder, props);

alias(XWorkConverter.class, StrutsConstants.STRUTS_XWORKCONVERTER, builder, props);

alias(TextProvider.class, StrutsConstants.STRUTS_XWORKTEXTPROVIDER, builder, props, Scope.DEFAULT);


我們關注的就是第一行,即這裏一個,其代碼爲 :

alias(ObjectFactory.class, “struts.objectFactory”, builder, props);


需要注意的是,這裏的 alias 和containerProvider 所提供的 alias 還不一樣。 containerProvider alias 是直接將給定的 name定義爲別名,而此處的 alias 是指將給定的 name所對應的值定義爲別名,相當於中間處了一次處理。爲什麼處理成這樣,其實就是一個擴展的過程。那麼我們來看一下相應的實現:


if (!builder.contains(type)) {// 相當於builder.contains(type,”default”)

   String foundName = props.getProperty(key, DEFAULT_BEAN_NAME);// 這裏的 DEFAULT_BEAN_NAME struts

if (builder.contains(type, foundName)) {

builder.alias(type, foundName, Container.DEFAULT_NAME);

   ……

首先尋找類型爲 objectFactory, 且key  default的聲明,如前所示,肯定找不到的啦。那麼就在定義文件中尋找聲明爲 struts.objectFactory 的值,在這裏我們找到了其值爲 spring ,接下來就將 key spring 的定義加個別名爲 default。在後面就找到了相應對象容器實現了。


需要注意的是, props.getProperty(key, DEFAULT_BEAN_NAME); 此句意爲在沒有找到值的情況下,就使用默認值,而默認值就是 struts ,意思是需要不存在 spring插件,則直接使用 key 爲struts 所對象的對象,即 StrutsObjectFactory 來作爲對象容器了。

<bean type="com.opensymphony.xwork2.FileManagerFactory" class="com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory" name="xwork" scope="singleton"/>

<bean type="com.opensymphony.xwork2.FileManagerFactory" class="com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory" name="struts" scope="singleton"/>


轉載請標明出處:i flym
本文地址:http://www.iflym.com/index.php/code/201204050001.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章