Tomcat源码系列8--Tomcat的JMX管理2
前面讲到了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注册也完毕。