Tomcat源码系列8--Tomcat的JMX管理2

xzkjgw 2011-04-01

前面讲到了JMX的体系,下面从Tomcat源代码启动过程分析MBeans组件注册到MBeanServer的过程 。 (org.apache.catalina.startup.Bootstrap.main(String))

public static void main(String args[]) {
       …
        if (daemon == null) {
            daemon = new Bootstrap();
            try {
                daemon.init();   ★1
            } catch (Throwable t) {
                t.printStackTrace();
                return;
            }
        }
        try {
            String command = "start";
            if (args.length > 0) {
                command = args[args.length - 1];
            }
            if (command.equals("startd")) {
                args[0] = "start";
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stopd")) {
                args[0] = "stop";
                daemon.stop();
            } else if (command.equals("start")) {
                daemon.setAwait(true);
                daemon.load(args);   ★2

             // Catalina的start方法被调用
                daemon.start();        ★3 
            } else if (command.equals("stop")) {
                daemon.stopServer(args);
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    

★1

daemon.init()会调用Bootstrap#createClassLoader方法,该方法会将对象名为StandardClassloader的MBean注册并返回Classloader。

(org.apache.catalina.startup.Bootstrap.createClassLoader(String, ClassLoader)) 
private ClassLoader createClassLoader(String name, ClassLoader parent) 
        throws Exception { 
…… 
ClassLoader classLoader = ClassLoaderFactory.createClassLoader 
            (unpacked, packed, urls, parent); 

        // Retrieving MBean server 
        MBeanServer mBeanServer = null; 
        if (MBeanServerFactory.findMBeanServer(null).size() > 0) { 
            mBeanServer = 
                (MBeanServer) MBeanServerFactory.findMBeanServer(null).get(0); 
        } else { 
            mBeanServer = MBeanServerFactory.createMBeanServer(); 
        } 

        //注册Server类加载器MBeans 
        ObjectName objectName = 
            new ObjectName("Catalina:type=ServerClassLoader,name=" + name); 
        mBeanServer.registerMBean(classLoader, objectName); 

        return classLoader; 
}

 

common、server、shared三个classloader会被依序生成,并被注册到mBeanServer中去。这三个Classloader都是StandardClassloader,并且实现了StandardClassloaderMBean接口。因为StandardClassloaderMBean接口没有暴露任何的属性和方法,所以在Jconsole窗口中将看不到StandardClassloader的属性和方法显示。

★2

daemon.load(args)是Catalina载入的过程,standardServer、StandardService、Connector将会被依次初始化并完成Mbean的注册。

1)StandardServer初始化注册。

(org.apache.catalina.core.StandardServer.initialize())

  
public void initialize() 
        throws LifecycleException 
    { 
        if (initialized) { 
                log.info(sm.getString("standardServer.initialize.initialized")); 
            return; 
        } 
        initialized = true; 

        if( oname==null ) { 
            try { 
               //注册StandardServer的MBeans 
                oname=new ObjectName( "Catalina:type=Server"); 
                Registry.getRegistry(null, null) 
                    .registerComponent(this, oname, null ); 
            } catch (Exception e) { 
                log.error("Error registering ",e); 
            } 
        } 
        
        // Initialize our defined Services 
        for (int i = 0; i < services.length; i++) { 
            services[i].initialize(); 
        } 
    }

 

2)StandardServer被注册后,它向外暴露了它的属性和await()和storeConfig()两个方法。

StandardService初始化并注册

(org.apache.catalina.core.StandardService.initialize()) 
public void initialize() 
            throws LifecycleException 
    { 
        if (initialized) { 
            log.info(sm.getString("standardService.initialize.initialized")); 
            return; 
        } 
        initialized = true; 

        if( oname==null ) { 
            try { 
                // StandardService的MBeans被注册 
                Container engine=this.getContainer(); 
                domain=engine.getName(); 
                oname=new ObjectName(domain + ":type=Service,serviceName="+name); 
                this.controller=oname; 
                Registry.getRegistry(null, null) 
                    .registerComponent(this, oname, null); 
            } catch (Exception e) { 
                log.error("Error registering ",e); 
            }  } 
            
            
        } 
        if( server==null ) { 
            
            ServerFactory.getServer().addService(this); 
        } 
        //初始化我们定义的连接 
        synchronized (connectors) { 
                for (int i = 0; i < connectors.length; i++) { 
                    connectors[i].initialize(); 
                } 
        }

 

StandardService被注册后,它向外暴露了它的属性和stop()和start()两个方法。在Jconsole中可以对这两个方法进行操作。

3)对象名为“Catalina:type=Connectorport=8080”、“Catalina:type=Connectorport=8009”的Connector被注册。

(org.apache.catalina.connector.Connector.initialize())

    
public void initialize() 
        throws LifecycleException 
    { 
        if (initialized) { 
            log.info(sm.getString("coyoteConnector.alreadyInitialized")); 
           return; 
        } 
        this.initialized = true; 

        if( oname == null && (container instanceof StandardEngine)) { 
            try { 
                // we are loaded directly, via API - and no name was given to us 
                StandardEngine cb=(StandardEngine)container; 
                String encodedAddr = null; 
                if (getAddress() != null) { 
                    encodedAddr = URLEncoder.encode(getAddress()); 
                } 
                String addSuffix=(getAddress()==null) ?"": ",address=" + encodedAddr; 
                oname=new ObjectName(cb.getName() + ":type=Connector,port="+ 
                        getPort() + addSuffix); 
                Registry.getRegistry(null, null) 
                    .registerComponent(this, oname, null); 
                controller=oname; 
            } catch (Exception e) { 
                log.error( "Error registering connector ", e); 
            } 
            log.debug("Creating name for connector " + oname); 
}

 

ConnectorMbean暴露了它的属性和Start、stop、pause、resume、init、destroy等方法。可以在Jconsole中对这些方法进行操作。

★3

daemon.start()Catalina.start()StandardServer.start()

下面是Catalina.start()代码片段。

(org.apache.catalina.core.StandardServer.start()) 
public void start() throws LifecycleException { 

        if (started) { 
            log.debug(sm.getString("standardServer.start.started")); 
            return; 
        } 

        //唤醒相关的生命周期监听者 
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null); 

        lifecycle.fireLifecycleEvent(START_EVENT, null); 
        started = true; 

        //启动我们定义的服务 
        synchronized (services) { 
            for (int i = 0; i < services.length; i++) { 
                if (services[i] instanceof Lifecycle) 
                    ((Lifecycle) services[i]).start(); 
            } 
        } 

        //唤醒相关的生命周期监听者 
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); 

    }

  Tomcat的配置文件Server.xml中的Server元素中定义了Listener元素,如下所示: 

<Server port="8005" shutdown="SHUTDOWN" debug="0"> 
... 
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" 
            debug="0"/> 
...

  它将给org.apache.catalina.core.StandardServer添加一个org.apache.catalina.mbeans.ServerLifecycleListener类型的监听器,当StandardServer实例启动的时候,会触发一个START_EVENT事件,如StandardServer类中定义的那样: 

public void start() throws LifecycleException { 
  ... 
  lifecycle.fireLifecycleEvent(START_EVENT, null); 
  ... 
}

  StandardServer对象停止的时候,会触发STOP_EVENT事件,如stop方法中定义的那样: 

public void stop() throws LifecycleException { 
  ... 
  lifecycle.fireLifecycleEvent(STOP_EVENT, null); 
  ... 
}

 

这些事件会导致ServerLifecycleListener中的lifecycleEvent方法被提交。下面展示了lifecycleEvent方法。

(org.apache.catalina.mbeans.ServerLifecycleListener.lifecycleEvent()) 
public void lifecycleEvent(LifecycleEvent event) { 
        Lifecycle lifecycle = event.getLifecycle(); 
        if (Lifecycle.START_EVENT.equals(event.getType())) { 
            if (lifecycle instanceof Server) { 
                createMBeans(); 
... 
        } 
... 
else if (Lifecycle.STOP_EVENT.equals(event.getType())) { 
            try { 
                if (lifecycle instanceof Server) { 
                    destroyMBeans((Server)lifecycle); 
                } 
                if (lifecycle instanceof Service) { 
                    destroyMBeans((Service)lifecycle); 
                } 
  }

 

从上面的代码可以看出当lifecycleEvent被调用时,由于START_EVENT事件被触发,createMBeans方法被调用,Catalina中所有MBeans将会生成。当StandardServer关闭时,STOP_EVENT事件被触发,destroyMBeans方法被调用,所有的MBeans将被销毁。

1)START_EVENT事件被触发,lifecycleEvent(START_EVENT)被调用,它会调用createMBeans方法。

(org.apache.catalina.mbeans.ServerLifecycleListener.createMBeans()) 
protected void createMBeans() { 

        try { 
            MBeanFactory factory = new MBeanFactory(); 
            createMBeans(factory);※1 
            createMBeans(ServerFactory.getServer());※2 
        } catch (MBeanException t) { 
            Exception e = t.getTargetException(); 
            if (e == null) 
                e = t; 
            log.error("createMBeans: MBeanException", e); 
        } catch (Throwable t) { 
            log.error("createMBeans: Throwable", t); 
        } 
    }

 

※1

该方法使用MBeanUtil类给MBeanFactory创建一个ObjectName并将其向MBean服务器注册。 
protected void createMBeans(MBeanFactory factory) throws Exception { 
        // Create the MBean for the MBeanFactory 
        if (log.isDebugEnabled()) 
            log.debug("Creating MBean for MBeanFactory " + factory); 
        MBeanUtils.createMBean(factory); 
    }

 

※2

该方法会将org.apache.catalina.Server对象创建模型MBean,使用for循环来迭代StandardServer实例中的所有Service对象。 
protected void createMBeans(Server server) throws Exception { 

        //为Server自身创建MBean 
        if (log.isDebugEnabled()) 
            log.debug("Creating MBean for Server " + server); 
        //MBeanUtils.createMBean(server); 
        if (server instanceof StandardServer) { 
            ((StandardServer) server).addPropertyChangeListener(this); 
        } 

        // 为global NamingResources创建MBean(如果有的话) 
        NamingResources resources = server.getGlobalNamingResources(); 
        if (resources != null) { 
            createMBeans(resources); 
        } 

        //为每个子服务创建MBeans 
        Service services[] = server.findServices(); 
        for (int i = 0; i < services.length; i++) { 
            // FIXME - Warp object hierarchy not currently supported 
            if (services[i].getContainer().getClass().getName().equals 
                ("org.apache.catalina.connector.warp.WarpEngine")) { 
                if (log.isDebugEnabled()) { 
                    log.debug("Skipping MBean for Service " + services[i]); 
                } 
                continue; 
            } 
            createMBeans(services[i]); 
        } 

    }

 

4)createMBeans(Serviceservice)创建一个MBean实例并调用createMBeans方法来为该服务所有的连接器和引擎创建MBean对象

(org.apache.catalina.mbeans.ServerLifecycleListener.createMBeans(Service)) 
protected void createMBeans(Service service) throws Exception { 

        //为Service自身创建MBean 
        if (log.isDebugEnabled()) 
            log.debug("Creating MBean for Service " + service); 
        //MBeanUtils.createMBean(service); 
        if (service instanceof StandardService) { 
            ((StandardService) service).addPropertyChangeListener(this); 
        } 

        // 为对应的连接器创建MBeans(8080,8009两个端口) 
        Connector connectors[] = service.findConnectors(); 
        for (int j = 0; j < connectors.length; j++) { 
            createMBeans(connectors[j]); 
        } 

        // 为关联的Engine创建MBean 
        Engine engine = (Engine) service.getContainer(); 
        if (engine != null) { 
            createMBeans(engine); 
        } 

    }

  5) createMBeans(engine)(org.apache.catalina.mbeans.ServerLifecycleListener.createMBeans(Engine)) 

protected void createMBeans(Engine engine) throws Exception { 

        //为Engine自身创建MBean 
        if (log.isDebugEnabled()) { 
            log.debug("Creating MBean for Engine " + engine); 
        } 
        //MBeanUtils.createMBean(engine); 
        engine.addContainerListener(this); 
        if (engine instanceof StandardEngine) { 
            ((StandardEngine) engine).addPropertyChangeListener(this); 
        } 

        //为关联的嵌套组件创建MBean 
        Realm eRealm = engine.getRealm(); 
        if (eRealm != null) { 
            if (log.isDebugEnabled()) 
                log.debug("Creating MBean for Realm " + eRealm); 
            //MBeanUtils.createMBean(eRealm); 
        } 

        // 为每个子Host创建MBeans 
        Container hosts[] = engine.findChildren(); 
        for (int j = 0; j < hosts.length; j++) { 
            createMBeans((Host) hosts[j]); 
        }

  6) createMBeans(host) ((org.apache.catalina.mbeans.ServerLifecycleListener.createMBeans(Host)) 

protected void createMBeans(Host host) throws Exception { 

        //为Host自身创建MBeans 
        if (log.isDebugEnabled()) { 
            log.debug("Creating MBean for Host " + host); 
        } 
        //MBeanUtils.createMBean(host); 
        host.addContainerListener(this); 
        if (host instanceof StandardHost) { 
            ((StandardHost) host).addPropertyChangeListener(this); 
        } 

        //为关联的嵌套组件创建MBean 
        Realm eRealm = host.getParent().getRealm(); 
        Realm hRealm = host.getRealm(); 
        if ((hRealm != null) && (hRealm != eRealm)) { 
            if (log.isDebugEnabled()) 
                log.debug("Creating MBean for Realm " + hRealm); 
            //MBeanUtils.createMBean(hRealm); 
        } 

        //为每个子Context创建MBeans 
        Container contexts[] = host.findChildren(); 
        for (int k = 0; k < contexts.length; k++) { 
            createMBeans((Context) contexts[k]); 
        } 

    }

  lifecycleEvent(START_EVENT)方法调用结束。调用会逐级返回, ((Lifecycle) services[i]).start()被调用。Deployer、GlobalRequestProcessor、JkHander、JkMain、JkWorkerEnv、Mapper、ThreadPool、Valve、ProtocolHandle等将会被注册。至此,Tomcat启动结束。JMX注册也完毕。

相关推荐