StandardEngine分析-tomcat6.x源码阅读

2013-09-16java

StandardEngine是什么

standardEngine是org.apache.catalina.Engine接口的标准实现,继承自ContainerBase,具有容器的功能。Engine的上级领导是Service,角色是负责管理虚拟主机,一个Engine就是一个Servlet容器,可以完成处理请求的任务,Engine从Connector链接器接收请求,而后分发到响应的虚拟主机处理。当须要tomcat须要使用多个虚拟机(配置jvmRoute)来实现负载均衡时,就须要用到Engine。在tomcat中,Engine不是必须的,可是tomcat都会启用Engine组件。Engine的功能:从Connector链接中接收请求,为请求选择虚拟机,分发到虚拟主机中处理请求。程序员

StandardEngine()
StandardEngine在默认构造器中准备所需资源的常量配置。调用super()方式初始化父类,也即ContainerBase;而后为pipeline阀门链(相似FilterChain)设置基准Valve,再者设置jvmRoute虚拟机路由,最后设置Engine后台处理线程的时间间隔。StandardEngine须要使用到这些内容来完成Engine的功能。apache

/**
	 * Create a new StandardEngine component with the default basic Valve.
	 */
	public StandardEngine() {

		super();
		pipeline.setBasic(new StandardEngineValve());
		/* Set the jmvRoute using the system property jvmRoute */
		try {
			//虚拟机路由,集群使用
			setJvmRoute(System.getProperty("jvmRoute"));
		} catch (Exception ex) {
		}
		// By default, the engine will hold the reloading thread
		backgroundProcessorDelay = 10;

	}

ContainerBase 是tomcat的基容器,实现Container容器接口,具备容器的特色和功能。StandardEngine继承了ContainerBase,Engine是容器,具有容器所具有的功能,Engine的父容器是Service,子容器是Host。tomcat

StandardEngineValve
Valve在tomcat中蛮重要的,由于全部的请求和响应都必需经过它来过滤,负责传递请求和响应信息,多个Valve组成Pipeline Valve链,每一个容器都具备一个Pipeline链,同时有一个BasicValve,BasicValve的做用很是重要,BasicValve在Pipeline链的尾部,负责调用传递请求信息,将控制转到子容器中的Pipeline中。每一个容器都有本身的BasicValve,StandardEngineValve就是Engine的BasicValve,继承自ValveBase。StandardEngineValve的方法invoke(Request, Response)负责将请求传递到Host组件中。网络

/**
	 * Select the appropriate child Host to process this request, based on the
	 * requested server name. If no matching Host can be found, return an
	 * appropriate HTTP error.
	 * 
	 * @param request
	 *            Request to be processed
	 * @param response
	 *            Response to be produced
	 * @param valveContext
	 *            Valve context used to forward to the next Valve
	 * 
	 * @exception IOException
	 *                if an input/output error occurred
	 * @exception ServletException
	 *                if a servlet error occurred
	 */
	public final void invoke(Request request, Response response)
			throws IOException, ServletException {

		// Select the Host to be used for this Request
		Host host = request.getHost();//选择host
		if (host == null) {
			response.sendError(
					HttpServletResponse.SC_BAD_REQUEST,
					sm.getString("standardEngine.noHost",
							request.getServerName()));
			return;
		}

		// Ask this Host to process this request
		host.getPipeline().getFirst().invoke(request, response);

	}

Valve
过滤Request/Response的接口,相似于Filter,二者功能相似,可是做用阶段不同。Valve由tomcat控制,多个Valve组成一个Pipeline Valve链,每个容器组件因为一个Pipeline,Filter是程序员定义逻辑,做用范围比Valve小。方法setNext(Valve)是设置本Valve的下一个Valve,Valve本身自己就是一个单向链表的节点,方法backgroundProcess()是后台任务处理,与容器的backgroundProcess()功能相同,方法invoke(Request, Response)是Valve的核心,也即它的功能点所在,负责过滤Request/Response或者传递控制。app

ValveBase
是Valve接口的实现,同时实现了Contained,MBeanRegistration接口,具有粘附容器和添加JMX监控的能力,方法backgroundProcess(),invoke(Request, Response)提供空实现,不作任何逻辑操做,将逻辑定义放置到子类中去。本类所完成的功能是Valve的next,保存Valve的下一个Valve,以及Contained接口的方法功能,依附容器。负载均衡

addChild(Container)
添加子容器,在方法内部是调用父类的方法添加子容器。容器嵌套是容器的基本功能之一。dom

init()
负责StandardEngine容器的初始化。主要完成如下几步操做:jvm

  • 设置以及初始化标记
  • 注册组件,添加MBServer监控
  • 对父容器Service组件状态的判断
/**
	 * 初始化
	 */
	public void init() {
		if (initialized)
			return;
		initialized = true;//标记初始化

		if (oname == null) {
			// not registered in JMX yet - standalone mode
			try {
				if (domain == null) {
					domain = getName();
				}
				if (log.isDebugEnabled())
					log.debug("Register " + domain);
				oname = new ObjectName(domain + ":type=Engine");
				controller = oname;
				//登记组件
				Registry.getRegistry(null, null).registerComponent(this, oname,
						null);
			} catch (Throwable t) {
				log.info("Error registering ", t);
			}
		}

		//MBean监控
		if (mbeansFile == null) {
			String defaultMBeansFile = getBaseDir()
					+ "/conf/tomcat5-mbeans.xml";
			File f = new File(defaultMBeansFile);
			if (f.exists())
				mbeansFile = f.getAbsolutePath();
		}
		if (mbeansFile != null) {
			readEngineMbeans();
		}
		if (mbeans != null) {
			try {
				Registry.getRegistry(null, null).invoke(mbeans, "init", false);
			} catch (Exception e) {
				log.error("Error in init() for " + mbeansFile, e);
			}
		}

		// not needed since the following if statement does the same thing the
		// right way
		// remove later after checking
		// if( service==null ) {
		// try {
		// ObjectName serviceName=getParentName();
		// if( mserver.isRegistered( serviceName )) {
		// log.info("Registering with the service ");
		// try {
		// mserver.invoke( serviceName, "setContainer",
		// new Object[] { this },
		// new String[] { "org.apache.catalina.Container" } );
		// } catch( Exception ex ) {
		// ex.printStackTrace();
		// }
		// }
		// } catch( Exception ex ) {
		// log.error("Error registering with service ");
		// }
		// }

		if (service == null) {//若是服务没有建立
			// for consistency...: we are probably in embeded mode
			try {
				//建立标准服务
				service = new StandardService();
				//设在容器所属
				service.setContainer(this);
				//初始化
				service.initialize();
				// Use same name for Service
				service.setName(getName());
			} catch (Throwable t) {
				log.error(t);
			}
		}

	}

start()
负责StandardEngine容器的启动任务,在start()方法中主要完成如下几步操做:ide

  • 断定是否已经启动和初始化
  • 启动realm权限管理组件,注册到MBServer
  • 调用基类的start()方法,启动容器,在父容器的start()方法中主要完成事件触发,logger组件,manager组件,realm组件,cluster组件,resource组件,pipeline组件,后台处理任务的启动
/**
	 * Start this Engine component.
	 * 启动Engine
	 * 
	 * @exception LifecycleException
	 *                if a startup error occurs
	 */
	public void start() throws LifecycleException {
		if (started) {
			return;
		}
		if (!initialized) {
			init();//初始化
		}

		// Look for a realm - that may have been configured earlier.
		// If the realm is added after context - it'll set itself.
		if (realm == null) {
			ObjectName realmName = null;
			try {
				realmName = new ObjectName(domain + ":type=Realm");
				if (mserver.isRegistered(realmName)) {
					mserver.invoke(realmName, "init", new Object[] {},
							new String[] {});
				}
			} catch (Throwable t) {
				log.debug("No realm for this engine " + realmName);
			}
		}

		// Log our server identification information
		// System.out.println(ServerInfo.getServerInfo());
		if (log.isInfoEnabled())
			log.info("Starting Servlet Engine: " + ServerInfo.getServerInfo());
		if (mbeans != null) {
			try {
				Registry.getRegistry(null, null).invoke(mbeans, "start", false);
			} catch (Exception e) {
				log.error("Error in start() for " + mbeansFile, e);
			}
		}

		// Standard container startup
		super.start();//启动

	}

stop()
负责中止Engine,主要完成如下几步:

  • 调用父类的stop()方法
  • 中止mbserver
/**
	 * 中止engine
	 */
	public void stop() throws LifecycleException {
		super.stop();//中止
		if (mbeans != null) {
			try {
				Registry.getRegistry(null, null).invoke(mbeans, "stop", false);
			} catch (Exception e) {
				log.error("Error in stop() for " + mbeansFile, e);
			}
		}
	}

destroy()
负责Engine销毁,清理占用资源。主要完成如下几个步骤:

  • 注销组件在mbserver,销毁组件。
/**
	 * 销毁Engine
	 */
	public void destroy() throws LifecycleException {
		if (!initialized)
			return;
		initialized = false;//标记未初始化

		// if we created it, make sure it's also destroyed
		// this call implizit this.stop()
		((StandardService) service).destroy();//销毁服务

		if (mbeans != null) {
			try {
				Registry.getRegistry(null, null).invoke(mbeans, "destroy",
						false);
			} catch (Exception e) {
				log.error(sm.getString(
						"standardEngine.unregister.mbeans.failed", mbeansFile),
						e);
			}
		}
		//
		if (mbeans != null) {
			try {
				for (int i = 0; i < mbeans.size(); i++) {
					Registry.getRegistry(null, null).unregisterComponent(
							(ObjectName) mbeans.get(i));
				}
			} catch (Exception e) {
				log.error(sm.getString(
						"standardEngine.unregister.mbeans.failed", mbeansFile),
						e);
			}
		}

		// force all metadata to be reloaded.
		// That doesn't affect existing beans. We should make it per
		// registry - and stop using the static.
		Registry.getRegistry(null, null).resetMetadata();

	}

logAccess(Request, Response, long, boolean)
日志记录方法,负责记录请求信息和响应信息,对于监控和调试颇有帮助。

AccessLogListener
负责监听请求,若是有请求则触发事件通知日志记录。

StandardEngine写的马马虎虎,认识程度还不够深。Engine做为链接Connector和Host的角色,Connector负责监听网络端口,接收请求信息,Engine负责将请求信息转到指定的Host中处理。Engine管理一个或者多个Host,能够在一个Engine中配置多个Host,不一样的Host应该由系统中配置的jvmRouteId来运行。Engine做为tomcat中标准的容器,衔接Service和Host,可是也能够没有Engine组件,能够直接将请求转到Servlet中处理,Engine的存在使得多个Host成为可能,并且层次结构更清晰,管理和维护组件更加容易。

该死的拖延症,我恨你

相关文章
相关标签/搜索