文档章节

刨根问底--struts--action通配符的配置与解析

cookqq
 cookqq
发布于 2013/02/19 11:18
字数 1573
阅读 444
收藏 1

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

cookqq

粉丝 118
博文 268
码字总数 156096
作品 0
海淀
技术主管
关于Apache Struts2 S2-057远程代码执行漏洞分析

  前言   Apache Struts框架是一个基于 Java Servlets,JavaBeans, 和 JavaServer Pages (JSP)的Web应用框架的开源项目,Struts基于Model-View-Controller (MVC)的设计模式,可以用来构件...

FreeBuf
08/28
0
0
Apache Struts 再曝高危远程代码执行漏洞,快升级!

Semmle 安全研究员 Man Yue Mo 近日披露了一个存在于流行的 Apache Struts Web 应用框架中的远程执行代码漏洞,可能允许远程攻击者在受影响的服务器上执行恶意代码。 该漏洞编号为 CVE-2018...

王练
08/26
0
0
刨根问底--struts--获得request-继承ServletRequestAware

《刨根问底--struts--获得request过程详解》详细分析了通过ServletActionContext.getRequest()获取request的详细过程,还可以通过action类继承ServletRequestAware获取rquest。ServletReques...

cookqq
2013/02/05
0
0
细谈Spring(十一)深入理解spring+struts2整合(附源码)

Spring和struts2是我们在项目架构中用的比较多的两个框架,怎么才能把这两个框架用好,怎么来整合是我们掌握运用这两个框架的关键点,下面我们就怎么来整合,从哪来整合,为什么要整合,从这...

youyu2299
2013/12/06
0
0
struts 笔记 action namespace

Struts请求处理流程 请求先被struts过滤器拦截下来,然后在struts中做处理,如果处理中未发现请求的地址,再发回tomcat服务器 让tomcat处理 自定义action 给在struts.xml中 action类添加cla...

脑丨残
2014/06/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

创建第一个react项目

sudo npm i -g create-react-app@1.5.2 create-react-app react-app cd react-apprm -rf package-lock.jsonrm -rf node_modules #主要是为了避免报错npm installnpm start......

lilugirl
52分钟前
1
0
在浏览器中进行深度学习:TensorFlow.js (八)生成对抗网络 (GAN)

Generative Adversarial Network 是深度学习中非常有趣的一种方法。GAN最早源自Ian Goodfellow的这篇论文。LeCun对GAN给出了极高的评价: “There are many interesting recent development...

naughty
今天
0
0
搬瓦工镜像站bwh1.net被DNS污染,国内打不开搬瓦工官网

今天下午(2018年10月17日),继搬瓦工主域名bandwagonhost.com被污染后,这个国内的镜像地址bwh1.net也被墙了。那么目前应该怎么访问搬瓦工官网呢? 消息来源:搬瓦工优惠网->搬瓦工镜像站b...

flyzy2005
今天
2
0
SpringBoot自动配置

本篇介绍下,如何通过springboot的自动配置,将公司项目内的依赖jar,不需要扫描路径,依赖jar的情况下,就能将jar内配置了@configuration注解的类,创建到IOC里面 介绍下开发环境 JDK版本1.8 spr...

贺小五
今天
3
0
命令行新建Maven多项目

参考地址 # DgroupId 可以理解为包名# DartifactId 可以理解为项目名mvn archetype:generate -DgroupId=cn.modfun -DartifactId=scaffold -DarchetypeArtifactId=maven-archetype-quickst......

阿白
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部