JSF REQUEST 过程

转载: http://developer.51cto.com/art/200907/137985.htm

 

FacesServlet初始化(FacesServlet#init

JSF请求处理过程中,系统启动的时候,会初始化FacesServlet,调用其中的init方法。里面主要做了两件事情,一个是初始化 FacesContextFactory,另外一个是初始化Lifecycle对象。在jsf-api项目中,FacesServlet类是一个 Servlet接口的实现类,而FacesContextFactory和Lifecycle都是接口。在jsf-ri项目中有这两个接口的实现类,分别 是com.sun.faces.context.FacesContextFactoryImpl和 com.sun.faces.lifecycle.LifecycleImpl类。一个想当然的事实:FacesServlet初始化的时候要根据一些配 置来判断具体的FacesContextFactory和Lifecycle实现类是什么,也就是在这里,“JSF标准”和“JSF实现”接轨了。想来 MyFaces等等的其他JSF实现应该不外乎两种方式,一种是改变FacesServlet的init方法中需要用到的配置的值,于是启用自己的 FacesContextFactory实现和Lifecycle实现,后面的处理过程就全部走自己的逻辑了。第二种方法笨一点,可能性不大,就是把 FacesServlet覆盖替换掉,其中也不需要读什么配置了,直接使用自己的实现类即可——不过这种做法估计不符合JSF规范,想来只有我等虾米民众 能做的出来。主要代码如下:

 

 facesContextFactory = (FacesContextFactory)FactoryFinder.
      getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);     
 LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.
      getFactory(FactoryFinder.LIFECYCLE_FACTORY); 
 

回头再来看初始化的结果,FacesContextFactory很明显是用来生产FacesContext这么个东西的。而 FacesContext可以看做是一个RequestWrapper(注意这个FaceContext和ServletContext不一 样,ServletContext是一个Web应用只有一个的全局对象,对应的是一个Web application,而一个FacesContext对应的是一个request,另外,RequestWrapper这个说法不严格,实际上 FacesContext里面也包装了ServletContext、Response等)。而LifeCycle可以看做是一个过滤器链(类似于 servlet规范里面的Filter Chain)。于是,整个JSF请求处理过程,实际上就是包装成为FaceContext的用户请求,通过类似于一个Filter Chain的LifeCycle的过程。

这总览,很明显是看FacesServlet的service方法。在FacesServlet的初始化过程中,构造出了全局的 FacesContextFactory对象和LifeCycle对象。可以把FacesContextFactory看做是一个“请求包装工厂”,于是 很明显,每当一个请求到达FacesServlet的时候,第一步便是拿着请求,到包装工厂里面包装一下,而包装的结果就是一个 FacesContext。代码如下:

FacesContext context = facesContextFactory.getFacesContext(servletConfig.getServletContext(), request, response, lifecycle);

在包装过程中,实际上是创建了一个com.sun.faces.context.FacesContextImpl对 象,FacesContextImpl类继承了jsf-api项目中的javax.faces.context.FacesContext。 FacesContextImpl的构造方法的第一个参数是一个叫做ExternalContext的接口的实现,查看其源代码,可以看到 ExternalContextImpl类耦合了Servlet API,而FacesContextImpl与Servlet API无关。实际上,在这里,做到了JSF可以不仅仅使用在Servlet环境中,正如ExternalContext接口的注释中所说,在 Servlet环境中使用JSF和在Portlet环境中使用JSF的不同,实际上就是使用了不同的ExternalContext。在 FacesContextFactoryImpl中构造FacesContextImpl的代码如下:

 

FacesContext ctx = new FacesContextImpl  
 (new ExternalContextImpl((ServletContext) sc,  
 (ServletRequest) request,(ServletResponse) response),  
 lifecycle); 
 

FacesContextImpl的构造方法中,还做了另外一件事情,就是根据配置确定了RenderKitFactory,显然不同的 RenderKitFactory可以产生不同的RenderKit,而不同RenderKit对象是针对不同客户端的,所以对于浏览器、移动设备等等, 会有不同的RenderKit。FacesContextImpl的构造方法中代码如下:

 

this.externalContext = ec;  
setCurrentInstance(this);  
 this.rkFactory = (RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY); 
 

在代码中我们经常使用FacesContext.getCurrentInstance()这个静态方法来获取与当前请求对应的 FacesContext对象,实际上是在FacesContext类里面有一个静态的ThreadLocal对象用来存放了当前请求线程对应的 FacesContext对象,于是上面的代码中setCurrentInstance(this)就是把当前构造出来的这个FacesContext对 象放到了ThreadLocal里面。

FacesContext创建出来以后,正如上面所说,要让他经过LifeCycle这个“Filter Chain”的逐步处理了。那么,Filter Chain里面放的是一个一个Filter,那么LifeCycle这个Chain里面放的是什么呢?答案是Phases。

FacesServlet让FaceContext通过LifeCycle的处理,分成了两个部分。一个部分是调用LifeCycle的 execute方法,执行逻辑,第二个部分是调用LifeCycle的render方法,呈现响应。FacesServlet.service中代码如 下:

 

    lifecycle.execute(context);  
    lifecycle.render(context); 
 

在LifeCycleImpl这个实现中,存放了一个Phase对象的数组,存放了7个Phase。其中第一个是null,然后依次是视图重建、应 用请求值、验证、更新模型值、执行应用程序、呈现响应。在execute方法中,调用了从视图重建开始到执行应用程序为止的5个Phase,而在 render方法中,调用了最后一个Phase,也就是呈现响应。在LifeCycleImpl类中,代码如下:

 

    //The Phase instance for the render() method  
        private Phase response = new RenderResponsePhase();  
     
        // The set of Phase instances that are executed by the execute() method  
        // in order by the ordinal property of each phase  
        private Phase[] phases = {  
            null, // ANY_PHASE placeholder, not a real Phase  
            new RestoreViewPhase(),  
            new ApplyRequestValuesPhase(),  
           new ProcessValidationsPhase(),  
           new UpdateModelValuesPhase(),  
          new InvokeApplicationPhase(),  
           response  
       }; 
 

在Servlet Filter中,可以由每一个Filter来决定是否要调用下一个Filter,从而决定是否让请求继续通过Filter Chains中的后续Filter,是链式调用的过程。而在LifeCycle的execute方法中,是用一个for循环顺序执行几个Phase。在每 一个Phase执行完之后,都会检查FaceContext对象中是否设置了停止后续处理直接呈现响应的标志(renderResponse)或者已经完 成了响应无需后续处理也不需要经过呈现响应阶段了(responseComplete),如果标志为true,那么就不再执行后续Phase。

LifeCycleImpl的execute方法主要代码如下:

 

    for (int i = 1, len = phases.length -1 ; i < len; i++) { // Skip ANY_PHASE placeholder  
     
                 if (context.getRenderResponse() ||  
                     context.getResponseComplete()) {  
                    break;  
                 }  
      
               phases[i].doPhase(context, this, listeners.listIterator());  
      
     } 
 

在LifeCycle的render方法中,也会检查FacesContext的responseComplete状态,如果为true,那么就不 再执行render Phase。于是我们此刻知道了在我们自己所写的一些代码或者JSF库里面的一些代码中,调用FacesContext的 responseComplete方法和renderResponse得作用原理。render方法主要代码如下:

 

 if (!context.getResponseComplete()) {  
        response.doPhase(context, this,listeners.listIterator());  
  }
 

另外注意,Phase这个概念、接口,以及几个实现,都是jsf-ri项目中的,而在jsf-api中不存在Phase这个概念。所以,LifeCycle是JSF标准的内容,而通过几个Phase来处理请求这种实现是sun的参考实现的做法。

最后,我们在JSF请求处理过程中可以看到对于每一个phase都调用了doPhase方法,同时把LifeCycle和FacesContext 当做参数传入了。值得注意的是,所谓的phaseListener,也传入了phase的doPhase方法中,由此大约能够想明白这个“阶段监听器”的 道理了。

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
后台采用apache服务器下的cgi处理c语言做微信小程序后台逻辑的脚本映射。PC端的服务器和客户端都是基于c语言写的。采用mysql数据库进行用户数据和聊天记录的存储。.zip C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值