本人博客开始迁移,博客整个架构自己搭建及编码 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();
}