刨根问底--struts--action通配符的配置与解析
博客专区 > cookqq 的博客 > 博客详情
刨根问底--struts--action通配符的配置与解析
cookqq 发表于5年前
刨根问底--struts--action通配符的配置与解析
  • 发表于 5年前
  • 阅读 443
  • 收藏 1
  • 点赞 0
  • 评论 0

【腾讯云】买域名送云解析+SSL证书+建站!>>>   

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













  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
cookqq
粉丝 115
博文 268
码字总数 156096
×
cookqq
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: