文档章节

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

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

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

粉丝 115
博文 268
码字总数 156096
作品 0
海淀
技术主管
MyEclipse 2017 整合SSH三大框架 到登录功能的实现(附源码)

本来以为学完Java EE之后用个三大框架没什么难度,结果昨天搭环境就搞了一晚上,还是靠室友找了半天才找出错误在哪,为了避免重复踩坑,而且目前网上用myeclipse2017做环境的教程还是蛮少的,...

xp731574722 ⋅ 03/02 ⋅ 0

ST2-045 For POC

转载请注明: 转载自Legend‘s BLog 本文链接地址: ST2-045 For POC 利用方法: 漏洞说明: Apache Struts 2被曝存在远程命令执行漏洞,漏洞编号S2-045,CVE编号CVE-2017-5638,在使用基于J...

apachecn_飞龙 ⋅ 2017/03/18 ⋅ 0

[Struts]Token 使用及原理

Struts Token 使用 1,先在一个Action中,调用saveToken(HttpServletRequest request)方法。然后转向带有表单的JSP页面。 2,在JSP页面提交表单给一个Action,再这个Action中进行是否为重复提...

thinkyoung ⋅ 2014/12/17 ⋅ 0

企业未修复Apache Struts 2漏洞致Web服务器被批量入侵

  0×1 概述   腾讯御见威胁情报中心监控发现,近期有大批企业网站的Web服务器遭到入侵并被植入挖矿木马。   安全人员分析发现被攻击网站服务器多存在Apache Struts 2 Jakarta Multipa...

FreeBuf ⋅ 04/29 ⋅ 0

Java 模板引擎 Beetl 2.8.0 发布,增加根对象支持

Java 模板引擎 Beetl 2.8.0 发布了,改进内容包括: #348 beetl 默认配置DefaultTemplateEngine #347 增加根对象支持 #346 允许设置全局 ClassLoader #345 支持struts2.5, 由于struts升级不...

闲大赋 ⋅ 04/23 ⋅ 0

闲谈“如何优化SSH框架的项目”

使用struts框架的好处之一就是所有action类继承一个基类,将访问控制在基类中处理.2.所有的action类都继承自baseaction,一个资源对应一个action类. 1.实现一个继承自struts的action的baseact...

thinkyoung ⋅ 2014/12/30 ⋅ 0

spring+springMvc+struts的SSH框架整合

小疯之前工作用的框架是o3w,SSH框架只是学习的时候用过,然后今天就回头来重新回顾SSH,就在网上找了一篇比较全而且比较简单的文章来帮助自己快速的理解SSH。 1.建立一个web项目 2.导入SSH...

野小疯 ⋅ 05/27 ⋅ 0

SSH (Struts2+Spring3.0+Hibernate3)框架(一) 理论

  典型的J2EE三层结构,分为表现层、中间层(业务逻辑层)和数据服务层。三层体系将业务规则、数据访问及合法性校验等工作放在中间层处理。客户端不直接与数据库交互,而是通过组件与中间层...

thinkyoung ⋅ 2014/12/17 ⋅ 0

开源产业不断发展,软件安全问题亟需得到关注

近日 Sonatype 发布了“2018年开源安全与风险分析”报告,该报告显示开源应用有大幅增长,在检测的应用中有96%包含开源组件,同时包含漏洞的软件数量也在不断增加。随着开源产业不断发展,目...

雨田桑 ⋅ 05/18 ⋅ 0

Struts2核心技术 (一)

struts2 struts2发展历史 经过很多年发展,Struts1已经成为了高度成熟的框架,但随着时间的发展,Struts1的局限性和缺点不断的暴露出来。 现在Struts已经分化成了两个框架 -第一个是在Strut...

architect刘源源 ⋅ 04/24 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JEPLUS主从功能配置之主从布局的设置——JEPLUS软件快速开发平台

JEPLUS主从功能配置之主从布局的设置 主从功能配置成功之后就需要根据业务需求来调整主从功能的数据显示方式,不同的主从数据的显示可以达到不同的主从数据显示效果,今天这篇笔记就讲解一下...

JEPLUS ⋅ 1分钟前 ⋅ 0

如何利用极光推送的新功能玩转世界杯营销

四年一次的世界杯已经于6月14日开赛!对于app的运营人员而言,这场远在俄罗斯的绿茵征战绝不仅仅牵动着球迷们的心,更拨动着众多互联网企业运营人员的神经。在这场营销大战中,push显然是app...

极光推送 ⋅ 5分钟前 ⋅ 0

Spring Cloud构建微服务架构-Hystrix依赖隔离

依赖隔离 “舱壁模式”对于熟悉Docker的读者一定不陌生,Docker通过“舱壁模式”实现进程的隔离,使得容器与容器之间不会互相影响。而Hystrix则使用该模式实现线程池的隔离,它会为每一个Hys...

itcloud ⋅ 7分钟前 ⋅ 0

SpringCloud 微服务 (八) 统一配置中心 Config Server&Client

壹 Spring Cloud Config 统一配置中心,方便维护配置文件,对一些公司对数据库密码等敏感的信息,对普通开发人员不公开,放在运维人员手上,对配置作一个隔离作用,另外项目线上的配置改动都要重新...

___大侠 ⋅ 11分钟前 ⋅ 0

echarts轮播地图并结合鼠标浮动点击

直接上代码 timeId=setInterval(function () { if(count<11){ myChart.dispatchAction({ type: 'downplay', ......

莫西摩西 ⋅ 14分钟前 ⋅ 0

基于 HTML5 的工业互联网 3D 可视化应用

工业企业中生产线处于高速运转,由工业设备所产生、采集和处理的数据量远大于企业中计算机和人工产生的数据,生产线的高速运转则对数据的实时性要求也更高。破解这些大数据就是企业在新一轮制...

xhload3d ⋅ 16分钟前 ⋅ 0

Nging启动与停止bat

start_nginx.bat @echo off  f:  cd F:\server\nginx-1.13.6  echo "nginx is starting on port 80"  start "" "nginx.exe"  exit   stop_nginx.bat @echo off::windows ......

Jay丶 ⋅ 18分钟前 ⋅ 0

SuRF: 一个优化的 Fast Succinct Tries

作者:唐刘 在前一篇文章中,我简单介绍了 Succinct Data Structure,这里我们继续介绍 SuRF。 Fast Succinct Tries SuRF 的核心数据结构就是 Fast Succinct Tries(FST),一种空间节省,支...

TiDB ⋅ 22分钟前 ⋅ 0

Kubernetes(六) - Secret和私有仓库认证

对一个公司来说安全也是最为重要的因为可能一旦出现安全问题可能这个公司就完了,所以对密码管理是一个长久不变的话题,Kubernetes对密码管理提供了Secret组件进行管理,最终映射成环境变量,文件...

喵了_个咪 ⋅ 24分钟前 ⋅ 0

DevOps的三大原则

DevOps的出现有其必然性。在软件开发生命周期中,遇到了两次瓶颈。第一次瓶颈是在需求阶段和开发阶段之间,针对不断变化的需求,对软件开发者提出了高要求,后来出现了敏捷方法论,强调适应需...

inidcard ⋅ 24分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部