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