DefaultConfiguration的RuntimeConfigurationImpl方法是对所有的packageConfig进行namespace的重新分类,这样做的目的在于当Xwork框架响应Http请求时,可以根据namepace进行URL匹配。
下面介绍这个方法的,它也用到了递归方法
这个方法主要是将程序配置中的数据结构创建成一个内部的运行中的配置文件,Xwork可以在其中查找一个action,他将数据结构扁平化处理,使数据更加容易的访问,他接受一个ActionConfig,将它的包和包的父包(EXTENDS关键字指定的包)的公共对象找到,例如:如果一个action包含了一个result,但是所在的包包含一个全局的result对象,那么这个action就将包含连个result对象。
1 /** 2 * This builds the internal runtime configuration used by Xwork for finding and configuring Actions from the 3 * programmatic configuration data structures. All of the old runtime configuration will be discarded and rebuilt. 4 * 5 * <p> 6 * It basically flattens the data structures to make the information easier to access. It will take 7 * an {@link ActionConfig} and combine its data with all inherited dast. For example, if the {@link ActionConfig} 8 * is in a package that contains a global result and it also contains a result, the resulting {@link ActionConfig} 9 * will have two results. 10 */ 11 protected synchronized RuntimeConfiguration buildRuntimeConfiguration() throws ConfigurationException {
命名空间和这个命名空间包含的所有的package包含的所有的action配置 12 Map<String, Map<String, ActionConfig>> namespaceActionConfigs = new LinkedHashMap<String, Map<String, ActionConfig>>();
命名空间和这个命名空间的所有的包的默认的action:即通过 <default-action-ref>属性配置的 13 Map<String, String> namespaceConfigs = new LinkedHashMap<String, String>(); 14 15 for (PackageConfig packageConfig : packageContexts.values()) { 16 如果当前的包属于抽象类型(不需要在包内定义action) 17 if (!packageConfig.isAbstract()) {
包对应的命名空间 18 String namespace = packageConfig.getNamespace();
查询出该命名空间对应的anction配置,其中这个map:configs
String对应的是action的名字,actionConfig对应的这个action的各种配置信息
19 Map<String, ActionConfig> configs = namespaceActionConfigs.get(namespace); 20 如果为空,证明刚刚开始初始化,这个命名空间对应的action的map信息,则重新生成一个
如果不为空,证明之前已经生成了该命名空间对应的action的map信息,
举例说明:一个配置文件中,有两个包,包A和包B的命名空间一致,上面的循环,先加载A,则
configs为空,但加载B的时候,针对该命名空间已经从在了configs,则不为空,包A和包B中的
action都加载到了这个map中 21 if (configs == null) { 22 configs = new LinkedHashMap<String, ActionConfig>(); 23 } 24 这个packageConfig.getAllActionConfigs()方法又用到了一个很经典的递归算法,下面对其进行分析 25 Map<String, ActionConfig> actionConfigs = packageConfig.getAllActionConfigs(); 26 这个actionConfig包含了针对该包和包的父亲(祖先,父亲的父亲的父亲等等)的所有的action的配置, 27 for (Object o : actionConfigs.keySet()) { 28 String actionName = (String) o; 29 ActionConfig baseConfig = actionConfigs.get(actionName); 30 configs.put(actionName, buildFullActionConfig(packageConfig, baseConfig)); 31 } 32 33 34 将该命名空间对应的所有存储action配置信息的map放到map映射中, 35 namespaceActionConfigs.put(namespace, configs);
下面的方式是获取命名空间中 36 if (packageConfig.getFullDefaultActionRef() != null) { 37 namespaceConfigs.put(namespace, packageConfig.getFullDefaultActionRef()); 38 } 39 } 40 } 41 42 return new RuntimeConfigurationImpl(namespaceActionConfigs, namespaceConfigs); 43 }
packageConfig.getAllActionConfigs()方法:注意递归方法的使用
1 /** 2 * returns the Map of all the ActionConfigs available in the current package. 3 * ActionConfigs defined in ancestor packages will be included in this Map. 4 * 5 * @return a Map of ActionConfig Objects with the action name as the key 6 * @see ActionConfig 7 */ 8 public Map<String, ActionConfig> getAllActionConfigs() { 9 Map<String, ActionConfig> retMap = new LinkedHashMap<String, ActionConfig>(); 10 判断有没有父亲。即是否存在extend属性
--找到所有的祖先的的actionConfig信息 11 if (!parents.isEmpty()) { 12 for (PackageConfig parent : parents) {
递归调用出现了。 13 retMap.putAll(parent.getAllActionConfigs()); 14 } 15 } 16 --加入当前的包对应的actionConfig信息 17 retMap.putAll(getActionConfigs()); 18 19 return retMap; 20 }
找到包对应的action-ref值的,一个包只能定义一个默认调用的action,当当前的action找不到的时候,那么调用他的父亲的父亲,一直向上遍历,直至找到为止,如果自动没知道,则返回null,这里也使用了递归的方法
1 /** 2 * gets the default action-ref name. If this is not set on this PackageConfig, it searches the parent 3 * PackageConfigs in order until it finds one. 4 */ 5 public String getFullDefaultActionRef() { 6 if ((defaultActionRef == null) && !parents.isEmpty()) { 7 for (PackageConfig parent : parents) {
--递归调用。 8 String parentDefault = parent.getFullDefaultActionRef(); 9 10 if (parentDefault != null) { 11 return parentDefault; 12 } 13 } 14 } 15 return defaultActionRef; 16 }