十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

自己动手写一个tomcat之6log以及pipeline和valve

自己动手写一个tomcat之6log以及pipeline和valve 写在前面源码 。本文看下log日志如何设计并开发valve和pipeline内容最终将log应用到valve和pipeline中。1log毫无疑问先定义日志接口/** * 日志底层接口 */publicinterfaceLogger{publicstaticfinalintFATALInteger.MIN_VALUE;publicstaticfinalintERROR1;publicstaticfinalintWARNING2;publicstaticfinalintINFORMATION3;publicstaticfinalintDEBUG4;publicStringgetInfo();publicintgetVerbosity();publicvoidsetVerbosity(intverbosity);publicvoidlog(Stringmessage);publicvoidlog(Exceptionexception,Stringmsg);publicvoidlog(Stringmessage,Throwablethrowable);publicvoidlog(Stringmessage,intverbosity);publicvoidlog(Stringmessage,Throwablethrowable,intverbosity);}定义base实现类packagemonitomcat.server.logger;// ...publicabstractclassLoggerBaseimplementsLogger{protectedintdebug0;protectedstaticfinalStringinfocom.minit.logger.LoggerBase/1.0;protectedintverbosityERROR;// ...publicabstractvoidlog(Stringmsg);/** * 核心方法 首先打印异常堆栈之后调用抽象方法public abstract void log(String msg);执行子类具体动作 * param msg * param throwable */publicvoidlog(Stringmsg,Throwablethrowable){CharArrayWriterbufnewCharArrayWriter();PrintWriterwriternewPrintWriter(buf);writer.println(msg);throwable.printStackTrace(writer);ThrowablerootCausenull;if(throwableinstanceofServletException)rootCause((ServletException)throwable).getRootCause();if(rootCause!null){writer.println(----- Root Cause -----);rootCause.printStackTrace(writer);}log(buf.toString());}// ...}其中public abstract void log(String msg);抽象方法需要在子类中给出具体的实现如下给出的实现类们分别是标准输出标准错误输出文件输出。我们来修改bootstrap修改context容器的日志为文件输出packagemonitomcat.server.startup;// .../** * 总的服务器对象负责管理类工作的对象类似于公司的管理层负责管理但不负责具体干活但管理本身不也是一种职责嘛所以也可以用单一职责来进行说明 */publicclassBootstrap{// ...publicstaticvoidmain(String[]args){// ...StandardContextservletContainernewStandardContext();// 设置日志servletContainer.setLogger(newFileLogger());// ...}}写日志输出到文件packagemonitomcat.server.connector.http;// ...publicclassHttpConnectorimplementsRunnable{// ...publicvoidrun(){// ...while(true){Socketsocketnull;try{// ...log(connector receive new request, assign to processor);// ...}catch(Exceptione){e.printStackTrace();}}}publicvoidstart(){ThreadthreadnewThread(this);// ...log(httpConnector.starting threadName);}// ...}测试一下2pipeline和valve本部分内容要达到的目的是通过责任链的方式来拦截一层一层容器的执行比如可以添加日志权限校验等。其中valve是执行的单元接口如下packagemonitomcat.server;importjava.io.IOException;importjavax.servlet.ServletException;/** * 容器执行逻辑单元 */publicinterfaceValve{publicStringgetInfo();publicContainergetContainer();publicvoidsetContainer(Containercontainer);publicvoidinvoke(Requestrequest,Responseresponse,ValveContextcontext)throwsIOException,ServletException;}base实现类packagemonitomcat.server.valves;importmonitomcat.server.Container;importmonitomcat.server.Valve;publicabstractclassValveBaseimplementsValve{protectedContainercontainernull;protectedintdebug0;protectedstaticStringinfocom.minit.valves.ValveBase/0.1;publicContainergetContainer(){return(container);}publicvoidsetContainer(Containercontainer){this.containercontainer;}publicintgetDebug(){return(this.debug);}publicvoidsetDebug(intdebug){this.debugdebug;}publicStringgetInfo(){return(info);}}为了维护valve的执行状态定义执行的上下文接口/** * valve执行上下文执行具体的链式调用动作 */publicinterfaceValveContext{publicStringgetInfo();publicvoidinvokeNext(Requestrequest,Responseresponse)throwsIOException,ServletException;}pipeline接口publicinterfacePipeline{publicValvegetBasic();publicvoidsetBasic(Valvevalve);publicvoidaddValve(Valvevalve);publicValve[]getValves();publicvoidinvoke(Requestrequest,Responseresponse)throwsIOException,ServletException;publicvoidremoveValve(Valvevalve);}pipeline实现类packagemonitomcat.server.core;// ...publicclassStandardPipelineimplementsPipeline{// ...publicvoidinvoke(Requestrequest,Responseresponse)throwsIOException,ServletException{System.out.println(StandardPipeline invoke());// Invoke the first Valve in this pipeline for this request(newStandardPipelineValveContext()).invokeNext(request,response);}// ...protectedclassStandardPipelineValveContextimplementsValveContext{protectedintstage0;publicStringgetInfo(){returninfo;}publicvoidinvokeNext(Requestrequest,Responseresponse)throwsIOException,ServletException{System.out.println(StandardPipelineValveContext invokeNext());intsubscriptstage;stagestage1;// Invoke the requested Valve for the current request threadif(subscriptvalves.length){valves[subscript].invoke(request,response,this);}elseif((subscriptvalves.length)(basic!null)){basic.invoke(request,response,this);}else{thrownewServletException(standardPipeline.noValve);}}}}这里StandardPipelineValveContext是ValveContext的实现类是一个内部类执行具体的链式调用动作所以pipeline这里更像是一个管理者角色并不是真正干活的但要维护一些信息比如valves数组。这里有一点需要注意必须要保证容器能够一层一层的调用所以这里定义basic valve的概念负责调用下一层container的pipeline定义context的basic valvepackagemonitomcat.server.core;// ...finalclassStandardContextValveextendsValveBase{// ...publicvoidinvoke(Requestrequest,Responseresponse,ValveContextvalveContext)throwsIOException,ServletException{// ...try{System.out.println(Call service());servletWrapper.invoke(request,response);}// ...}}负责调用wrapper container的pipeline。定义wrapper basic valve:packagemonitomcat.server.core;// ...publicclassStandardWrapperValveextendsValveBase{Overridepublicvoidinvoke(Requestrequest,Responseresponse,ValveContextcontext)throwsIOException,ServletException{// ...if(instance!null){instance.service(requestFacade,responseFacade);}}}负责调用最终的servlet就执行到头了。接着我们只需要为每一层的容器定义其pipeline然后设置basic valve以及其他valve就可以了这里pipeline的创建,以及添加valve的动作因为是公共的所以我们放在base容器中packagemonitomcat.server.core;// ...publicabstractclassContainerBaseimplementsContainer,Pipeline{// ...protectedPipelinepipelinenewStandardPipeline(this);publicPipelinegetPipeline(){return(this.pipeline);}publicvoidinvoke(Requestrequest,Responseresponse)throwsIOException,ServletException{// System.out.println(ContainerBase invoke());pipeline.invoke(request,response);}publicsynchronizedvoidaddValve(Valvevalve){pipeline.addValve(valve);}publicValvegetBasic(){return(pipeline.getBasic());}publicValve[]getValves(){return(pipeline.getValves());}publicsynchronizedvoidremoveValve(Valvevalve){pipeline.removeValve(valve);}publicvoidsetBasic(Valvevalve){pipeline.setBasic(valve);}}发起执行的动作在ServletProcessor中如下publicclassServletProcessor{privateHttpConnectorconnector;publicServletProcessor(HttpConnectorconnector){this.connectorconnector;}// public void process(HttpRequestImpl request, HttpResponseImpl response) throws IOException, ServletException {publicvoidprocess(Requestrequest,Responseresponse)throwsIOException,ServletException{this.connector.getContainer().invoke(request,response);}}这样程序就按照如下图的方式执行了写在后面参考文章列表手把手带你写一个 MiniTomcat 。
返回列表