StandardEngine分析-tomcat6.x源码阅读
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的功能。
/** * 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。
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或者传递控制。
ValveBase
是Valve接口的实现,同时实现了Contained,MBeanRegistration接口,具备粘附容器和添加JMX监控的能力,方法backgroundProcess(),invoke(Request, Response)提供空实现,不做任何逻辑操作,将逻辑定义放置到子类中去。本类所完成的功能是Valve的next,保存Valve的下一个Valve,以及Contained接口的方法功能,依附容器。
addChild(Container)
添加子容器,在方法内部是调用父类的方法添加子容器。容器嵌套是容器的基本功能之一。
init()
负责StandardEngine容器的初始化。主要完成以下几步操作:
/** * 初始化 */ 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()方法中主要完成以下几步操作:
/** * 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,主要完成以下几步:
/** * 停止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销毁,清理占用资源。主要完成以下几个步骤:
/** * 销毁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成为可能,而且层次结构更清晰,管理和维护组件更加容易。
网页名称:StandardEngine分析-tomcat6.x源码阅读
当前网址:http://scyanting.com/article/cjidii.html