Tomcat源码阅读之Mapper分析

Mapper对于Tomcat或者jetty这种应用服务器来说应该算是非常重要的一个东西了。。

首先来说它是干嘛用的,听名字就基本上能猜出来,对于请求,对这个请求进行路由,交给应该负责处理这个请求的最终代码就是Mapp而应该干的或。。

对于servlet来说,对应的就是一次http请求该交给哪一个servlet来处理。

其实以前在看jetty的代码的时候就相当于看过了一种实现的方式,jetty采用的是一种类似于tries(字典树)的查询来进行请求的路由。。。感觉还算是蛮不错的吧。。毕竟字典树在做基于字符串的查询效率还是很高的。。

那么接下来来大体的来说一下tomcat是怎么实现的吧。。。嗯,最关键的就是:二分搜索,字符串也是可以排序的嘛,也就是字典序,那么也就可以做二分搜索咯。。。


在开始具体的代码之前,先来看一个简略的结构图吧:



这个是整个Mapper的比较简单的总体的结构层次图吧,通过以前的分析我们知道,在tomcat服务器中,可以有多个service,每个service只能有一个engine,而一个engine可以部署多个host,一个host又可以部署多个context,而mapper对象是属于service所拥有的。。。也符合上面的层次图。。。


先来看看上面提到一些对象的定义吧,他们都是定义在Mapper里面的嵌套类:

    protected abstract static class MapElement<T> {

        public String name = null;  //名字
        public T object = null;  //对应的对象,例如是host对象,context对象或者wrapper对象啥的

    }


    // ------------------------------------------------------- Host Inner Class


    protected static final class MappedHost  //对host的map信息
        extends MapElement<Host> {

        public ContextList contextList = null;   //有一个contextlist

    }


    // ------------------------------------------------ ContextList Inner Class


    protected static final class ContextList {  //在mappedhost里面将会用其来存拥有的context的信息

        public MappedContext[] contexts = new MappedContext[0];  //mappedcontext对象的数组
        public int nesting = 0;   //所有的context的path中,最多的斜线数目

    }


    // ---------------------------------------------------- Context Inner Class


    protected static final class MappedContext extends MapElement<Context> {  //对context的map的信息
        public ContextVersion[] versions = new ContextVersion[0];  //版本的数组
    }


    protected static final class ContextVersion extends MapElement<Context> {  //某个context的某个版本的具体信息
        public String path = null;   //path
        public String[] welcomeResources = new String[0];   //welcome的数据
        public WebResourceRoot resources = null;   //操作当前web应用程序的资源
        public MappedWrapper defaultWrapper = null;   //默认的wrapper
        public MappedWrapper[] exactWrappers = new MappedWrapper[0];    //对wrapper的精确的map
        public MappedWrapper[] wildcardWrappers = new MappedWrapper[0];   //基于通配符的map
        public MappedWrapper[] extensionWrappers = new MappedWrapper[0];   //基于扩展名的map
        public int nesting = 0;   // 属于这个context的所有servlet的path里面最大斜线数目

    }


    // ---------------------------------------------------- Wrapper Inner Class


    protected static class MappedWrapper  //对wrapper对象的map信息
        extends MapElement<Wrapper> {

        public boolean jspWildCard = false;
        public boolean resourceOnly = false;
    }

这里最基本的类型是MapElement,它是一个泛型吧,属性首先是名字,对于host来说,那么就是host的名字了,对于context来说那就是context的path了。。。。以此类推。。


然后是MappedHost的定义,这里其实也就稍微扩展了一下MapElement类型吧,加入了一个ContextList,看名字就知道它用于保存当前host所拥有的所有的host对象。。。ContextList的定义我们可以看到其实也是用数组来保存MappedContext对象的。。。


然后是MappedContext的定义,这里扩展了 一个ContextVersion的数组,因对于context来说,可能在时间段上同一个context可能会重新部署啥的,就涉及到不同的版本了。。当然一般情况下这个数组的长度都是为1的,也就是只有一个版本。。。


接下来就是ContextVersion定义了,可以将它理解为具体的一个context的map的信息,有path,defaultWrapper,以及wrapper的匹配什么的。。分为精确匹配,通配符匹配,和扩展名匹配。。


最后就是MappedWrapper了,扩展的东西不多吧。。主要是一些标记。。。


好啦,接下来来具体的看看Mapper的定义,先来看看它的重要的属性吧:

    protected MappedHost[] hosts = new MappedHost[0];  // 对host的map信息

    protected String defaultHostName = null;  // engine使用的默认的host名字


    protected Map<Context, ContextVersion> contextObjectToContextVersionMap =   //对context的map信息,key是context对象,value是contextVersion对象
            new ConcurrentHashMap<>();

hosts数组,用于保存所有的host的map信息,然后又一个defaultHostName,在engine对象的定义中有一个defaultHostName属性,就是对应的这里。。。

然后就是一个map,用于将context对象与具体的contextVersion匹配起来。。。


好啦,接下来来看看如何在mapper中添加对一个host。。

    //添加host的map信息,第一个参数是hsot的名字,第二个是别名,第三个是host对象
    public synchronized void addHost(String name, String[] aliases,  
                                     Host host) {
        MappedHost[] newHosts = new MappedHost[hosts.length + 1];  //创建MappedHost对象的数组,这里长度需要加1
        MappedHost newHost = new MappedHost();   //创建一个MappedHost对象,用于保存host的map信息
        ContextList contextList = new ContextList();   //ContextList对象,用于保存context
        newHost.name = name;   //设置名字
        newHost.contextList = contextList;   //设置
        newHost.object = host;  //设置对应的host对象
        if (insertMap(hosts, newHosts, newHost)) {  //这里需要复制以前的host的map信息,并维护好排序
            hosts = newHosts;  //指向新新的数组
        }
        for (int i = 0; i < aliases.length; i++) {  //遍历这个host的所有的别名,为每一个别名都创建一次map信息,感觉这里做了挺多重复的事情
            newHosts = new MappedHost[hosts.length + 1];
            newHost = new MappedHost();
            newHost.name = aliases[i];
            newHost.conte
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值