原文名稱:使用 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(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