摘要:上文说HttpProcessor在启动之后监听socket端口,如果socket端口有请求,该方法就调用方法connector.getContainer().invoke(request, response);去处理请求。接下来,我们来看看容器在整个请求处理过程中的作用。 本文介绍最重要的四个容器: 1、Engine:表示整个Catalina的servlet引擎 2、Host:表示一个拥
上文说HttpProcessor在启动之后监听socket端口,如果socket端口有请求,该方法就调用方法connector.getContainer().invoke(request,response);去处理请求。接下来,我们来看看容器在整个请求处理过程中的作用。
本文介绍最重要的四个容器:
1、Engine:表示整个Catalina的servlet引擎
2、Host:表示一个拥有数个上下文的虚拟主机
3、Context:表示一个Web应用,一个context包含一个或多个wrapper
4、warpper:表示一个独立的servlet
这四个容器都实现了接口Container,所以他们都叫容器,他们之间有上下级别的关系,如图所示
1、简单容器
连接器管理socket监听,一旦页面有对应端口请求,那么容器就来处理。也就是上文中说的这个方法。
connector.getContainer().invoke(request,response);
我们在页面请求servlet是这个样子的:http://localhost:8080/Primitive。那么这个URI是如何解析的呢?
首先引入Maper接口,mapper接口和容器关联,负责具体处理我们的URI对应的servlet类。
publicinterfaceMapper{ /** *mapper关联的容器 */ publicContainergetContainer(); /** 设置关联容器 */ publicvoidsetContainer(Containercontainer); /**返回mapper对应的协议 *ReturntheprotocolforwhichthisMapperisresponsible. */ publicStringgetProtocol(); /** *设置mapper对应的协议 */ publicvoidsetProtocol(Stringprotocol); /**返回该请求的负责容器。*/ publicContainermap(Requestrequest,booleanupdate); } 简单的Mapper接口实现如下: publicclassSimpleContextMapperimplementsMapper{ /**mapper关联容器 */ privateSimpleContextcontext=null; publicContainergetContainer(){ return(context); } publicvoidsetContainer(Containercontainer){ if(!(containerinstanceofSimpleContext)) thrownewIllegalArgumentException ("Illegaltypeofcontainer"); context=(SimpleContext)container; } publicStringgetProtocol(){ returnnull; } publicvoidsetProtocol(Stringprotocol){ } /**返回处理这个请求的子容器 */ publicContainermap(Requestrequest,booleanupdate){ //获取URI StringcontextPath= ((HttpServletRequest)request.getRequest()).getContextPath(); StringrequestURI=((HttpRequest)request).getDecodedRequestURI(); StringrelativeURI=requestURI.substring(contextPath.length()); // Wrapperwrapper=null; StringservletPath=relativeURI; StringpathInfo=null; //从容器的servletMappings字段获得servlet名称。 Stringname=context.findServletMapping(relativeURI); if(name!=null) //从容器的children字段中获得该servlet名称对应的Wrapper类实例 wrapper=(Wrapper)context.findChild(name); return(wrapper); } }
代码中map方法返回了我们请求URI对应的处理容器。简单的处理容器主要就是处理我们请求的servlet。具体的他包含两个方面的内容:
1、生成servlet实例。
2、为管道添加处理逻辑。
生成servlet实例主要就是通过类加载器加载servlet类。然后实例化该servlet类并且调用init()方法执行实例初始化过程。为管道添加逻辑就涉及到了管道和Vavle的概念。
管道其实就是一个责任链,为servlet初始化后添加一些处理逻辑Vavle。看代码:
publicclassSimplePipelineimplementsPipeline{ publicSimplePipeline(Containercontainer){ setContainer(container); } //基础的Valve可有可无 protectedValvebasic=null; //该Pipleline关联的容器 protectedContainercontainer=null; //该pipeline包含的valves数组 protectedValvevalves[]=newValve[0]; //添加valve publicvoidaddValve(Valvevalve){ if(valveinstanceofContained) //为valve设置容器为当前类的容器。 ((Contained)valve).setContainer(this.container); //线程安全扩容放置新增vavles synchronized(valves){ Valveresults[]=newValve[valves.length+1]; System.arraycopy(valves,0,results,0,valves.length); results[valves.length]=valve; valves=results; } } publicvoidinvoke(Requestrequest,Responseresponse) throwsIOException,ServletException{ //生成内部类SimplePipelineValveContext调用责任链 (newSimplePipelineValveContext()).invokeNext(request,response); } publicvoidremoveValve(Valvevalve){ } //内部类 protectedclassSimplePipelineValveContextimplementsValveContext{ protectedintstage=0; publicStringgetInfo(){ returnnull; } //责任链调用 publicvoidinvokeNext(Requestrequest,Responseresponse) throwsIOException,ServletException{ intsubscript=stage; stage=stage+1; //InvoketherequestedValveforthecurrentrequestthread if(subscript<valves.length){ valves[subscript].invoke(request,response,this); } elseif((subscript==valves.length)&&(basic!=null)){ basic.invoke(request,response,this); } else{ thrownewServletException("Novalve"); } } }//endofinnerclass }
2、管道的原理。
管道其实就是一个责任链,他把需要处理的逻辑全部都组装成为Vavle然后一个一个的去执行,没执行一个首先是要去调下一个Vavle,如果调用到底部没有其他了那就执行逻辑,返回之后就继续执行它上面的Vavle。
代码实现:
从连接器过来的请求首先调用了容器的invoker()。invoker里面就是去执行管道里面的逻辑处理。
publicvoidinvoke(Requestrequest,Responseresponse) throwsIOException,ServletException{ pipeline.invoke(request,response); } 管道的invoker需要调用责任链,那么他首先生成了内部类,然后调用invokeNext()方法去执行业务逻辑。 publicvoidinvoke(Requestrequest,Responseresponse) throwsIOException,ServletException{ //InvokethefirstValveinthispipelineforthisrequest (newSimplePipelineValveContext()).invokeNext(request,response); } protectedclassSimplePipelineValveContextimplementsValveContext{ protectedintstage=0; publicStringgetInfo(){ returnnull; } publicvoidinvokeNext(Requestrequest,Responseresponse) throwsIOException,ServletException{ intsubscript=stage; stage=stage+1; //InvoketherequestedValveforthecurrentrequestthread if(subscript<valves.length){ valves[subscript].invoke(request,response,this); } elseif((subscript==valves.length)&&(basic!=null)){ basic.invoke(request,response,this); } else{ thrownewServletException("Novalve"); } } }//endofinnerclass
相关文章推荐
虚拟主机的专业参数,分别都是什么意思?2022-09-09
中非域名注册规则是怎样的?注册域名有什么用处? 2022-01-10
HostEase新年活动促销 美国/香港主机全场低至五折2021-12-28
HostGator下载完整备份教程分享2021-12-28
Flink中有界数据与无界数据的示例分析2021-12-28