知识库--StandardContextMapper(60)

来源:互联网 发布:淘宝店铺换ip有影响吗 编辑:程序博客网 时间:2024/05/16 05:32

StandardContextMapper

//StandardContextValve首先获取wrapper
For each incoming request, the invoke method of the StandardContext’s pipeline’s basic valve will be called. The basic valve for a StandardContext is repesented by the org.apache.catalina.core.StandardContextValve class. The first thing that StandardContextValve.invoke needs to do is obtain a wrapper that will handle the request.

//valve使用mapper找到对应的wrapper
In tomcat 4, the StandardContextValve instance looks in its contianing StandardContext. The StandardContextValve uses the context’s mapper to find a suitable wrapper. Once it obtains the wrapper, it calls the invoke method of the wrapper. Before delving into what the StandardContextValve does, here presents an introduction to the mapper component.

//父类 add defaultMapper
The ContainerBase class, the parent class of StandardContext, defines the addDefaultMapper method to add a default mapper as follows:

    protected void addDefaultMapper(String mapperClass){        //Do we really need a Mapper        if(mapperClass == null){            return;        }        if(mapper.size()>=1)            return;        //Instantiate and add a default Mapperr        try{            Class clazz = Class.forName(mapperClass);            Mapper mapper = (Mapper)clazz.newInstance();            mapper.setProtocol("http");            addMapper(mapper);        }catch(Exception e){log(...)}    }

The StandardContext class calls the addDefaultMapper method from its start method, passing the mapperClass variable:

public synchronized void start() throws LifecycleException{    ...    if(ok){        try{            addDefaultMapper(this.mapperClass);        }...    }}

The StandardContext class defines the mapperClass variable as follows:

private String mapperClass = "org.apache.catalina.core.StandardContextMapper";

//mapper 关联 container
You must then associate a mapper with a container by calling the mapper’s setContainer method, passing the instance of the container. The implementation class of the org.apache.catalina.Mapper interface for StandardContextMapper is org.apache.catalina.core.StandardContextMapper. StandardContextMapper can only be associated with a context, as indicated by its setContainer method.

public void setContainer(Container container){    if(!(container instanceof StandardContext))        throw new IllegalArgumentException(..);    context = (StandardContext)container;}

The most important method in a mapper is map, whitch returns a child container to handler an HTTP request. The signature of this method is as follows:

public Container map(Request request, boolean update)

In StandardContextMapper, the map method returns a wrapper that will handle a request. If the appropriate wrapper cannot be found, the map method returns null.

//ContainerBase 调用findMapper寻找 对应协议的mapper
The StandardContextValve instance calls the context’s map method for each incoming HTTP request, passing a org.apache.catalina.Request object. The map method (in the parent class ContainerBase)first obtains a mapper for a particular protocol by calling the findMapper method, and then calling the mapper’s map method.

    //select the Mapper we will use    Mapper mapper= findMapper(request.getRequest().getProtocol());    if(mapper == null)        return null;    return (mapper.map(request,update));

The map method in StandardContextMapper first identifies the context-relative URI to be mapped:

    String contextPath = ((HttpServletRequest)request.getRequest()).getContextPath();    String requestURI = ((HttpRequest)request).getDecodedRequestURI();    String relativeURI = requestURI.substring(contextPath.length());

//四条规则 map方法获取wrapper
It then attemps to obtain a wrapper by applying four matching rules:

//Apply the standard request URI mapping rules from the specificationWrapper wrapper = null;String servletPath = relativeURI;Stirng pathIfno = null;String name = null;//Rule 1 - Exact Matchif(wrapper == null){    if(!(relativeURI.equals("/")))        name = context.findServletMapping(relativeURI);    if(name != null){        wrapper = (Wrapper)context.findChild(name);    }    if(wrapper != null){        servletPath = relativeURI;        pathInfo = null;    }}//Rule 2 - Prefix Match 前缀匹配if(wrapper == null){    servletPath = relativeURI;    while(true){        name = context.findServletMapping(servletPath + "/*");        if(name != null){            wrapper = (Wrapper)context.findChild(name);        }        if(wrapper != null){            pathInfo = relativeURI.subString(servletPath.length());            if(pathInfo.length() == 0){                pathInfo = null;            }            break;        }        int slash = servletPath.lastIndexOf('/');        if(slash < 0){            break;        }        servletPath = servletPath.substring(0,slash);    }}//Rule 3 - Extension Matchif(wrapper == null){    int slash  = relativeURI.lastIndexOf('/');    if(slash >= 0){        String last = relativeURI.substring(slash);        int period = last.lastIndexOf('.');        if(period >= 0){            String pattern = "*"+last.substring(period);            name = context.findServletMapping(pattern);            if(name!=null)                wrapper = (Wrapper)context.findChild(name);            if(wrapper!=null){                servletPath = relativeURI;                pathInfo = null;            }        }    }}//Rule 4 -- Default Matchif(wrapper == null){    name = context.findServletMapping("/");    if(name != null){        wrapper = (Wrapper)context.findChild(name);    }    if(wrapper != null){        servletPath =  relativeURI;        pathInfo = null;    }}

How does the context have such information as the servlet mappings? recall…

context.addServletMapping("/Primitive","Primitive");context.addServletMapping("/Modern","Modern");

It also adds the wrappers as children of the context:

context.addChild(wrapper1);context.addChild(wrapper2);

Tomcat 5 removed the Mapper interface and its related classes. In fact, the StandardContextValve class’s invoke method obtains the suitable wrapper from the request object:

Wrapper wrapper = request.getWrapper();

which indicates that the mapping information is encapsulated in the request object.

0 0
原创粉丝点击