[Tomcat6.0源码]请求的处理三Mapper、JMX

CoyoteAdapter.service():

            if (postParseRequest(req, request, res, response)) {
                // Calling the container
            	//Http1.1调用StandardEngineValve.invoke(request,response)
                connector.getContainer().getPipeline().getFirst().invoke(request, response);
                ......
            }

postParseRequest()还需要对请求进行封装:

        connector.getMapper().map(serverName, decodedURI, 
                                  request.getMappingData());
        request.setContext((Context) request.getMappingData().context);

这个connector是在Connector.init()方法中,创建CayoteAdapter对象的时候赋值的:

adapter = new CoyoteAdapter(this);

this即使Connector对象自身,connector.getMapper()返回的是Mapper对象,在Connector属性中new出来的:

protected Mapper mapper = new Mapper();

Mapper.map():

    public void map(MessageBytes host, MessageBytes uri,
                    MappingData mappingData)
        throws Exception {

        if (host.isNull()) {
            host.getCharChunk().append(defaultHostName);
        }
        host.toChars();
        uri.toChars();
        internalMap(host.getCharChunk(), uri.getCharChunk(), mappingData);

    }

根据uri将,mapper中的Host、Context、Wrapper对象赋值到request.mappingData中。

Mapper.internalMap():

    /**
     * Map the specified URI.
     */
    private final void internalMap(CharChunk host, CharChunk uri,
                                   MappingData mappingData)
        throws Exception {

        uri.setLimit(-1);

        Context[] contexts = null;
        Context context = null;
        int nesting = 0;

        // Virtual host mapping
        if (mappingData.host == null) {
            Host[] hosts = this.hosts;
            int pos = findIgnoreCase(hosts, host);
            if ((pos != -1) && (host.equalsIgnoreCase(hosts[pos].name))) {
                mappingData.host = hosts[pos].object;
                contexts = hosts[pos].contextList.contexts;
                nesting = hosts[pos].contextList.nesting;
            } else {
                if (defaultHostName == null) {
                    return;
                }
                pos = find(hosts, defaultHostName);
                if ((pos != -1) && (defaultHostName.equals(hosts[pos].name))) {
                    mappingData.host = hosts[pos].object;
                    contexts = hosts[pos].contextList.contexts;
                    nesting = hosts[pos].contextList.nesting;
                } else {
                    return;
                }
            }
        }

        // Context mapping
        if (mappingData.context == null) {
            int pos = find(contexts, uri);
            if (pos == -1) {
                return;
            }

            int lastSlash = -1;
            int uriEnd = uri.getEnd();
            int length = -1;
            boolean found = false;
            while (pos >= 0) {
                if (uri.startsWith(contexts[pos].name)) {
                    length = contexts[pos].name.length();
                    if (uri.getLength() == length) {
                        found = true;
                        break;
                    } else if (uri.startsWithIgnoreCase("/", length)) {
                        found = true;
                        break;
                    }
                }
                if (lastSlash == -1) {
                    lastSlash = nthSlash(uri, nesting + 1);
                } else {
                    lastSlash = lastSlash(uri);
                }
                uri.setEnd(lastSlash);
                pos = find(contexts, uri);
            }
            uri.setEnd(uriEnd);

            if (!found) {
                if (contexts[0].name.equals("")) {
                    context = contexts[0];
                }
            } else {
                context = contexts[pos];
            }
            if (context != null) {
                mappingData.context = context.object;
                mappingData.contextPath.setString(context.name);
            }
        }

        // Wrapper mapping
        if ((context != null) && (mappingData.wrapper == null)) {
            internalMapWrapper(context, uri, mappingData);
        }

    }

而Mapper中的Host、Context、Wrapper类只是简单的内部类,并非之前的StandardContext、StandardHost、StandardWrapper。

    // ------------------------------------------------------- Host Inner Class
   protected static final class Host
        extends MapElement {

        public ContextList contextList = null;

    }


    // ------------------------------------------------ ContextList Inner Class
   protected static final class ContextList {

        public Context[] contexts = new Context[0];
        public int nesting = 0;

    }


    // ---------------------------------------------------- Context Inner Class
   protected static final class Context
        extends MapElement {

        public String path = null;
        public String[] welcomeResources = new String[0];
        public javax.naming.Context resources = null;
        public Wrapper defaultWrapper = null;
        public Wrapper[] exactWrappers = new Wrapper[0];
        public Wrapper[] wildcardWrappers = new Wrapper[0];
        public Wrapper[] extensionWrappers = new Wrapper[0];
        public int nesting = 0;

    }


    // ---------------------------------------------------- Wrapper Inner Class
    protected static class Wrapper
        extends MapElement {

        public String path = null;
        public boolean jspWildCard = false;
    }

他们都继承了MapElement类:

    protected static abstract class MapElement {

        public String name = null;
        public Object object = null;

    }

就几个字段,用来存储所有的容器类。那这些类是什么时候存储的,又是如何存储的呢?

Connector.start():

            mapperListener.setDomain( domain );
            //mapperListener.setEngine( service.getContainer().getName() );
            mapperListener.init();

mapperListener来自Connector的属性:

protected MapperListener mapperListener = new MapperListener(mapper, this);

传入的参数是前面的mapper对象和Connector自身对象。

MapperListener.init():

public void init() {

        try {

            mBeanServer = Registry.getRegistry(null, null).getMBeanServer();

            registerEngine();

            // Query hosts
            String onStr = domain + ":type=Host,*";
            ObjectName objectName = new ObjectName(onStr);
            Set set = mBeanServer.queryMBeans(objectName, null);
            Iterator iterator = set.iterator();
            while (iterator.hasNext()) {
                ObjectInstance oi = (ObjectInstance) iterator.next();
                registerHost(oi.getObjectName());
            }


            // Query contexts
            onStr = "*:j2eeType=WebModule,*";
            objectName = new ObjectName(onStr);
            set = mBeanServer.queryMBeans(objectName, null);
            iterator = set.iterator();
            while (iterator.hasNext()) {
                ObjectInstance oi = (ObjectInstance) iterator.next();
                registerContext(oi.getObjectName());
            }

            // Query wrappers
            onStr = "*:j2eeType=Servlet,*";
            objectName = new ObjectName(onStr);
            set = mBeanServer.queryMBeans(objectName, null);
            iterator = set.iterator();
            while (iterator.hasNext()) {
                ObjectInstance oi = (ObjectInstance) iterator.next();
                registerWrapper(oi.getObjectName());
            }

            onStr = "JMImplementation:type=MBeanServerDelegate";
            objectName = new ObjectName(onStr);
            mBeanServer.addNotificationListener(objectName, this, null, null);

        } catch (Exception e) {
            log.warn("Error registering contexts",e);
        }

    }

MapperListener.registerContext():

    private void registerContext(ObjectName objectName)
        throws Exception {

        String name = objectName.getKeyProperty("name");
        
        // If the domain is the same with ours or the engine 
        // name attribute is the same... - then it's ours
        String targetDomain=objectName.getDomain();
        if( ! domain.equals( targetDomain )) {
            try {
                targetDomain = (String) mBeanServer.getAttribute
                    (objectName, "engineName");
            } catch (Exception e) {
                // Ignore
            }
            if( ! domain.equals( targetDomain )) {
                // not ours
                return;
            }
        }

        String hostName = null;
        String contextName = null;
        if (name.startsWith("//")) {
            name = name.substring(2);
        }
        int slash = name.indexOf("/");
        if (slash != -1) {
            hostName = name.substring(0, slash);
            contextName = name.substring(slash);
        } else {
            return;
        }
        // Special case for the root context
        if (contextName.equals("/")) {
            contextName = "";
        }

        if(log.isDebugEnabled())
             log.debug(sm.getString
                  ("mapperListener.registerContext", contextName));

        Object context = 
            mBeanServer.invoke(objectName, "findMappingObject", null, null);
            //mBeanServer.getAttribute(objectName, "mappingObject");
        javax.naming.Context resources = (javax.naming.Context)
            mBeanServer.invoke(objectName, "findStaticResources", null, null);
            //mBeanServer.getAttribute(objectName, "staticResources");
        String[] welcomeFiles = (String[])
            mBeanServer.getAttribute(objectName, "welcomeFiles");

        mapper.addContext(hostName, contextName, context, 
                          welcomeFiles, resources);

    }

Tomcat使用JMX管理资源。

JmxMBeanServer作为管理MBean的容器:

1.使用registerMBean(Object object, ObjectName name)往里边保存bean。registerMBean的第一个参数为继承了BaseModuleBean的对象。第二个参数为封装了唯一性String的ObjectName对象。

2.需要调用BaseModuleBean的方法时,用MBeanServer.invoke()方法。第一个参数为唯一性ObjectName,第二个参数为需要调用的方法名。MBeanServer根据ObjectName找到对应的BaseModuleBean,然后调用其名为第二个参数的方法。

Object context = mBeanServer.invoke(objectName, "findMappingObject", null, null);

调用objectName对应的StandardContext对象的findMappingObject方法,最终将返回StandardContext对象自身。

3.需要返回 BaseModuleBean的属性时,用MBeanServer.getAttribute() 方法。第一个参数为唯一性ObjectName,第二个参数为参数名。

        String[] welcomeFiles = (String[])
            mBeanServer.getAttribute(objectName, "welcomeFiles");

将返回StandardContext对象的的welcomeFiles属性。
那么这些相关的bean是什么时候放到MBeanServer中的呢?

StandardContext.start()时候已经进行了注册。

    private void preRegisterJMX() {
        try {
            StandardHost host = (StandardHost) getParent();
            if ((oname == null) 
                || (oname.getKeyProperty("j2eeType") == null)) {
                oname = createObjectName(host.getDomain(), host.getJmxName());
                controller = oname;
            }
        } catch(Exception ex) {
            if(log.isInfoEnabled())
                log.info("Error registering ctx with jmx " + this + " " +
                     oname + " " + ex.toString(), ex );
        }
    }

createObjectName():

    public ObjectName createObjectName(String hostDomain, ObjectName parentName)
            throws MalformedObjectNameException
    {
        String onameStr;
        StandardHost hst=(StandardHost)getParent();
        
        String pathName=getName();
        String hostName=getParent().getName();
        String name= "//" + ((hostName==null)? "DEFAULT" : hostName) +
                (("".equals(pathName))?"/":pathName );

        String suffix=",J2EEApplication=" +
                getJ2EEApplication() + ",J2EEServer=" +
                getJ2EEServer();

        onameStr="j2eeType=WebModule,name=" + name + suffix;
        if( log.isDebugEnabled())
            log.debug("Registering " + onameStr + " for " + oname);
        
        // default case - no domain explictely set.
        if( getDomain() == null ) domain=hst.getDomain();

        ObjectName oname=new ObjectName(getDomain() + ":" + onameStr);
        return oname;        
    }    

以上只是创建ObjectName,registerJMX();

    private void registerJMX() {
        try {
            if (log.isDebugEnabled()) {
                log.debug("Checking for " + oname );
            }
            if(! Registry.getRegistry(null, null)
                .getMBeanServer().isRegistered(oname)) {
                controller = oname;
                Registry.getRegistry(null, null)
                    .registerComponent(this, oname, null);
                
                // Send j2ee.object.created notification 
                if (this.getObjectName() != null) {
                    Notification notification = new Notification(
                                                        "j2ee.object.created", 
                                                        this.getObjectName(), 
                                                        sequenceNumber++);
                    broadcaster.sendNotification(notification);
                }
            }
            Container children[] = findChildren();
            for (int i=0; children!=null && i<children.length; i++) {
                ((StandardWrapper)children[i]).registerJMX( this );
            }
        } catch (Exception ex) {
            if(log.isInfoEnabled())
                log.info("Error registering wrapper with jmx " + this + " " +
                    oname + " " + ex.toString(), ex );
        }
    }

Registry.getRegistry(null, null).registerComponent(this, oname, null);

    public void registerComponent(Object bean, ObjectName oname, String type)
           throws Exception
    {
        if( log.isDebugEnabled() ) {
            log.debug( "Managed= "+ oname);
        }

        if( bean ==null ) {
            log.error("Null component " + oname );
            return;
        }

        try {
            if( type==null ) {
                type=bean.getClass().getName();
            }

            ManagedBean managed = findManagedBean(bean.getClass(), type);

            // The real mbean is created and registered
            DynamicMBean mbean = managed.createMBean(bean);

            if(  getMBeanServer().isRegistered( oname )) {
                if( log.isDebugEnabled()) {
                    log.debug("Unregistering existing component " + oname );
                }
                getMBeanServer().unregisterMBean( oname );
            }

            getMBeanServer().registerMBean( mbean, oname);
        } catch( Exception ex) {
            log.error("Error registering " + oname, ex );
            throw ex;
        }
    }

getMBeanServer().registerMBean( mbean, oname);既是将mbean存入MBeanServer。 

回到MapperListener.registerContext():

        mapper.addContext(hostName, contextName, context, 
                          welcomeFiles, resources);

Mapper.addContext():

    public void addContext
        (String hostName, String path, Object context,
         String[] welcomeResources, javax.naming.Context resources) {

        Host[] hosts = this.hosts;
        int pos = find(hosts, hostName);
        if( pos <0 ) {
            addHost(hostName, new String[0], "");
            hosts = this.hosts;
            pos = find(hosts, hostName);
        }
        if (pos < 0) {
            logger.error("No host found: " + hostName);
        }
        Host host = hosts[pos];
        if (host.name.equals(hostName)) {
            int slashCount = slashCount(path);
            synchronized (host) {
                Context[] contexts = host.contextList.contexts;
                // Update nesting
                if (slashCount > host.contextList.nesting) {
                    host.contextList.nesting = slashCount;
                }
                Context[] newContexts = new Context[contexts.length + 1];
                Context newContext = new Context();
                newContext.name = path;
                newContext.object = context;
                newContext.welcomeResources = welcomeResources;
                newContext.resources = resources;
                if (insertMap(contexts, newContexts, newContext)) {
                    host.contextList.contexts = newContexts;
                }
            }
        }

    }

创建一个Mapper内部类Context。将StandardContext保存到Context.object属性中,再将Context添加的上级组件Host的ContextList中。
也就是说到组件启动完成后,服务器上的Host、Context、Wrapper对象都会保存到Connector对象的mapper属性中,等待请求。

当收到请求后,会调用Mapper.map()对uri进行解析,匹配出相关的Host、Context、Wrapper对象,放置到请求request的参数中。

还是以Context为例,在Mapper的internalMap方法中:

        // Context mapping
        if (mappingData.context == null) {
            int pos = find(contexts, uri);
            if (pos == -1) {
                return;
            }

            int lastSlash = -1;
            int uriEnd = uri.getEnd();
            int length = -1;
            boolean found = false;
            while (pos >= 0) {
                if (uri.startsWith(contexts[pos].name)) {
                    length = contexts[pos].name.length();
                    if (uri.getLength() == length) {
                        found = true;
                        break;
                    } else if (uri.startsWithIgnoreCase("/", length)) {
                        found = true;
                        break;
                    }
                }
                if (lastSlash == -1) {
                    lastSlash = nthSlash(uri, nesting + 1);
                } else {
                    lastSlash = lastSlash(uri);
                }
                uri.setEnd(lastSlash);
                pos = find(contexts, uri);
            }
            uri.setEnd(uriEnd);

            if (!found) {
                if (contexts[0].name.equals("")) {
                    context = contexts[0];
                }
            } else {
                context = contexts[pos];
            }
            if (context != null) {
                mappingData.context = context.object;
                mappingData.contextPath.setString(context.name);
            }
        }

将context.object(StandardContext对象)设置到mappingData.context,Mapper.map()执行完后,会将mappingData.context赋值个request.context,CoyoteAdapter.postParseRequest():

request.setContext((Context) request.getMappingData().context);

至此,request已经封装的差不多了,已经知道要交由哪些组件来处理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值