本人博客开始迁移,博客整个架构自己搭建及编码 http://www.cookqq.com
《刨根问底-struts-怎么预加载配置的相应的信息》详细的分析了struts.xml文件是什么时候加载的?加载的时机。但是没有分析到通配符是怎么保存的?是以什么形式保存的?带着这些疑问来读这篇文章。
其中reloadContainer()方法重新加载一下容器,最后一行
rebuildRuntimeConfiguration();重建运行时的配置
1、DefaultConfiguration类rebuildRuntimeConfiguration()代码:
public void rebuildRuntimeConfiguration() { runtimeConfiguration = buildRuntimeConfiguration(); }
2、buildRuntimeConfiguration()代码:
protected synchronized RuntimeConfiguration buildRuntimeConfiguration() throws ConfigurationException { Map<String, Map<String, ActionConfig>> namespaceActionConfigs = new LinkedHashMap<String, Map<String, ActionConfig>>(); Map<String, String> namespaceConfigs = new LinkedHashMap<String, String>(); for (PackageConfig packageConfig : packageContexts.values()) { if (!packageConfig.isAbstract()) { //判断这个package配置是否是抽象 String namespace = packageConfig.getNamespace(); //获得namespace Map<String, ActionConfig> configs = namespaceActionConfigs.get(namespace); if (configs == null) {//如果没有和names相应的configs,就创建 configs = new LinkedHashMap<String, ActionConfig>(); } Map<String, ActionConfig> actionConfigs = packageConfig.getAllActionConfigs(); for (Object o : actionConfigs.keySet()) { String actionName = (String) o; ActionConfig baseConfig = actionConfigs.get(actionName); configs.put(actionName, buildFullActionConfig(packageConfig, baseConfig)); //buildFullActionConfig()创建一个ActionConfig配置信息更全的对象 } namespaceActionConfigs.put(namespace, configs); if (packageConfig.getFullDefaultActionRef() != null) { namespaceConfigs.put(namespace, packageConfig.getFullDefaultActionRef()); // packageConfig.getFullDefaultActionRef()获得默认的action } } } return new RuntimeConfigurationImpl(namespaceActionConfigs, namespaceConfigs); }
注释:(1)//buildFullActionConfig()创建一个ActionConfig配置信息更全的对象
private ActionConfig buildFullActionConfig(PackageConfig packageContext, ActionConfig baseConfig) throws ConfigurationException { Map<String, String> params = new TreeMap<String, String>(baseConfig.getParams()); Map<String, ResultConfig> results = new TreeMap<String, ResultConfig>(); if (!baseConfig.getPackageName().equals(packageContext.getName()) && packageContexts.containsKey(baseConfig.getPackageName())) { results.putAll(packageContexts.get(baseConfig.getPackageName()).getAllGlobalResults()); } else { results.putAll(packageContext.getAllGlobalResults()); //这里package标签中配置的global-results } results.putAll(baseConfig.getResults()); //在把标签action中配置的result标签,添加到results setDefaultResults(results, packageContext); List<InterceptorMapping> interceptors = new ArrayList<InterceptorMapping>(baseConfig.getInterceptors()); //设置拦截器 if (interceptors.size() <= 0) { String defaultInterceptorRefName = packageContext.getFullDefaultInterceptorRef(); if (defaultInterceptorRefName != null) { interceptors.addAll(InterceptorBuilder.constructInterceptorReference(new PackageConfig.Builder(packageContext), defaultInterceptorRefName, new LinkedHashMap<String, String>(), packageContext.getLocation(), objectFactory)); } } //创建ActionConfig对象 return new ActionConfig.Builder(baseConfig) .addParams(params) .addResultConfigs(results) .defaultClassName(packageContext.getDefaultClassRef()) // fill in default if non class has been provided .interceptors(interceptors) .addExceptionMappings(packageContext.getAllExceptionMappingConfigs()) .build(); }
(2)创建RuntimeConfigurationImpl对象
3、RuntimeConfigurationImpl的构造函数
public RuntimeConfigurationImpl(Map<String, Map<String, ActionConfig>> namespaceActionConfigs, Map<String, String> namespaceConfigs) { this.namespaceActionConfigs = namespaceActionConfigs; this.namespaceConfigs = namespaceConfigs; PatternMatcher<int[]> matcher = container.getInstance(PatternMatcher.class); //matcher对应的是WildcardHelper this.namespaceActionConfigMatchers = new LinkedHashMap<String, ActionConfigMatcher>(); this.namespaceMatcher = new NamespaceMatcher(matcher, namespaceActionConfigs.keySet()); //创建NamespaceMatcher对象,names的通配符处理对象 for (String ns : namespaceActionConfigs.keySet()) { namespaceActionConfigMatchers.put(ns, new ActionConfigMatcher(matcher, namespaceActionConfigs.get(ns), true));//创建ActionConfigMatcher对象,action的通配符处理对象 } }
注释:(1)首先创建NamespaceMatcher对象,对namespace通配符的处理。
(2)ns是namespace
(3)namespaceActionConfigMatchers保存着每个namespace中action的通配符处理的对象
(4)ActionConfigMatcher对actionName通配符的处理
4、ActionConfigMatcher的构造函数
public ActionConfigMatcher(PatternMatcher<?> patternMatcher, Map<String, ActionConfig> configs, boolean looseMatch) { super(patternMatcher); for (String name : configs.keySet()) { addPattern(name, configs.get(name), looseMatch); //增加模式 } }
注释:主要是遍历configs,给每一个action添加相应的模式
5、addPattern()方法
//添加模式 public void addPattern(String name, E target, boolean looseMatch) { //便于查看name=“dog_*”; Object pattern; //wildcard 是WildcardHelper的实例 if (!wildcard.isLiteral(name)) { //判断name是否是文字,也就是判断时候包含“*” if (looseMatch && (name.length() > 0) && (name.charAt(0) == '/')) { //判断name第一个字符是否是'/' name = name.substring(1); } if (log.isDebugEnabled()) { log.debug("Compiling pattern '" + name + "'"); } pattern = wildcard.compilePattern(name); compiledPatterns.add(new Mapping<E>(name, pattern, target)); //这里添加模式 name=dog_* ,pattern = [-4, 100, 111, 103, 95, -1, -5] if (looseMatch) { int lastStar = name.lastIndexOf('*'); if (lastStar > 1 && lastStar == name.length() - 1) { if (name.charAt(lastStar - 1) != '*') { pattern = wildcard.compilePattern(name.substring(0, lastStar - 1)); compiledPatterns.add(new Mapping<E>(name, pattern, target));//这里添加模式 name=dog_* ,pattern = [-4, 100, 111, 103, -5] } } } } }
注释:到这里就把action中对象的模式创建好了,并且都保存到变量compiledPatterns中,后面分析怎么获取相应的模式,并且解析出来。
6、前面分析过action的执行过程,其中DefaultActionProxy类中的prepare() 方法会根据namespace和actionName获取相应的配置信息:
protected void prepare() { String profileKey = "create DefaultActionProxy: "; try { UtilTimerStack.push(profileKey); config = configuration.getRuntimeConfiguration().getActionConfig(namespace, actionName); 。。。 }
注释:configuration.getRuntimeConfiguration()获得就是上面步骤1创建的 RuntimeConfigurationImpl对象,
7、getActionConfig()方法
public synchronized ActionConfig getActionConfig(String namespace, String name) { ActionConfig config = findActionConfigInNamespace(namespace, name); // try wildcarded namespaces if (config == null) { NamespaceMatch match = namespaceMatcher.match(namespace); if (match != null) { config = findActionConfigInNamespace(match.getPattern(), name); // If config found, place all the matches found in the namespace processing in the action's parameters if (config != null) { config = new ActionConfig.Builder(config) .addParams(match.getVariables()) .build(); } } } // fail over to empty namespace if ((config == null) && (namespace != null) && (!"".equals(namespace.trim()))) { config = findActionConfigInNamespace("", name); } return config; }
注释:(1)根据namespace和 name通过findActionConfigInNamespace()获取相应的ActionConfig,步骤8重点分析
(2)如果config为空,就根据通配符在获取一次
(3)如果config=null并且namespace也不为null,就把namespace设置为“” 在获取一次,config = findActionConfigInNamespace("", name)。
8、findActionConfigInNamespace()方法:
ActionConfig findActionConfigInNamespace(String namespace, String name) { ActionConfig config = null; if (namespace == null) { namespace = ""; } Map<String, ActionConfig> actions = namespaceActionConfigs.get(namespace); if (actions != null) { config = actions.get(name); // Check wildcards 检查通配符 if (config == null) { config = namespaceActionConfigMatchers.get(namespace).match(name); // fail over to default action if (config == null) { String defaultActionRef = namespaceConfigs.get(namespace); if (defaultActionRef != null) { config = actions.get(defaultActionRef); } } } } return config; }
注释:(1)首先根据namespace获取actions
(2)根据name获取config,如果没有找到,在通过通配符模式查找。
(3)namespaceActionConfigMatchers在步骤3中赋值,key是namespace,获取相应的ActionConfigMatcher对象。
9、ActionConfigMatcher中match()方法:
public E match(String potentialMatch) {//potentialMatch= “dog_add” E config = null; if (compiledPatterns.size() > 0) { if (log.isDebugEnabled()) { log.debug("Attempting to match '" + potentialMatch + "' to a wildcard pattern, "+ compiledPatterns.size() + " available"); } Map<String,String> vars = new LinkedHashMap<String,String>(); for (Mapping<E> m : compiledPatterns) { if (wildcard.match(vars, potentialMatch, m.getPattern())) { if (log.isDebugEnabled()) { log.debug("Value matches pattern '" + m.getOriginalPattern() + "'"); } config = convert(potentialMatch, m.getTarget(), vars); //创建actionMapping对象,请看ActionConfigMatcher类中的convert()方法 break; } } } return config; }
注释:(1)compiledPatterns在步骤5addPattern()方法中添加匹配模板
(2)wildcard是WildcardHelper类型,然后调用match方法进行匹配,有时间的看以看看,这是笔者做的例子:
String potentialMatch = "dog_add";
int[] expr = {-4, 100, 111, 103, 95, -1, -5};
vars = {0=dog_add, 1=add}
(3)方法convert()创建一个新的ActionConfig对象
10、ActionConfigMatcher类中的convert()方法
@Override public ActionConfig convert(String path, ActionConfig orig, Map<String, String> vars) { String className = convertParam(orig.getClassName(), vars); String methodName = convertParam(orig.getMethodName(), vars); String pkgName = convertParam(orig.getPackageName(), vars); Map<String,String> params = replaceParameters(orig.getParams(), vars); Map<String,ResultConfig> results = new LinkedHashMap<String,ResultConfig>(); for (String name : orig.getResults().keySet()) { ResultConfig result = orig.getResults().get(name); name = convertParam(name, vars); ResultConfig r = new ResultConfig.Builder(name, convertParam(result.getClassName(), vars)) .addParams(replaceParameters(result.getParams(), vars)) .build(); results.put(name, r); } List<ExceptionMappingConfig> exs = new ArrayList<ExceptionMappingConfig>(); for (ExceptionMappingConfig ex : orig.getExceptionMappings()) { String name = convertParam(ex.getName(), vars); String exClassName = convertParam(ex.getExceptionClassName(), vars); String exResult = convertParam(ex.getResult(), vars); Map<String,String> exParams = replaceParameters(ex.getParams(), vars); ExceptionMappingConfig e = new ExceptionMappingConfig.Builder(name, exClassName, exResult).addParams(exParams).build(); exs.add(e); }
注释:(1)根据获得vars,去寻找真实的className,methodName等等。
(2)convertParam()方法兑换参数
(3)创建新的ActionConfig,到这通过通配符,寻找了正确的action相应的信息。
11、convertParam()
//参数类型map的vars保存着相应的通配符信息 protected String convertParam(String val, Map<String, String> vars) { if (val == null) { return null; } int len = val.length(); StringBuilder ret = new StringBuilder(); char c; String varVal; for (int x=0; x<len; x++) { c = val.charAt(x); if (x < len - 2 && c == '{' && '}' == val.charAt(x+2)) { varVal = (String)vars.get(String.valueOf(val.charAt(x + 1))); if (varVal != null) { ret.append(varVal); } x += 2; } else { ret.append(c); } } return ret.toString(); }