JSF 源代码赏析之FacesServlet

学习JSF 多日,现在开始看看源代码。
首先是FacesServlet类了,作为一个前端控制器,每一个JSF请求都要通过FacesServlet,然后再到其他阶段,那么,FacesServlet 到底做了些什么操作呢?

文件头部的注释
  1. /**
  2. *

    FacesServlet is a servlet that manages the request

  3. * processing lifecycle for web applications that are utilizing JavaServer
  4. * Faces to construct the user interface.

  5. */
头部注释说的很明白,管理请求的处理周期。至于怎么管理,下面先来看一看到底声明了什么变量
变量
  1. public static final String CONFIG_FILES_ATTR =
  2. "javax.faces.CONFIG_FILES";
  3. public static final String LIFECYCLE_ID_ATTR =
  4. "javax.faces.LIFECYCLE_ID";
  5. private static final Logger LOGGER =
  6. Logger.getLogger("javax.faces.webapp", "javax.faces.LogStrings");
  7. private FacesContextFactory facesContextFactory = null;
  8. private Lifecycle lifecycle = null;
  9. private ServletConfig servletConfig = null;

上面这些变量都是FacesServlet的全局变量,也就是整个JSF 应用的全局变量,其中最主要的我都加粗了,可以看出,主要涉及到FacesContextFactory、LifeCycle和ServletConfig对象,其中的ServletConfig对象不难理解,基于Servlet技术的表现层框架都需要这个类,而FacesContextFactory和LifeCycle则有些研究了。

FacesContextFactory是一个实现了工厂模式的抽象类,用来创建(如果没有的话)和返回一个FacesContext实例,并且把这个实例初始化,以便处理request和response对象。至于这个FacesContext对象,则是始终贯彻在JSF中的一个对象,下面自然会慢慢讲解,现在需要知道的是,FacesContext也是一个抽象类就可以。
现在先看一下FacesContextFactory对象和FacesContext的关系。顾名思义,工厂模式,就是专门生产产品的,FacesContextFactory工厂则是专门产生FacesContext对象的,FacesContextFactory对象提供了下面的方法:
FacesContextFactory
  1. public abstract FacesContext getFacesContext
  2. (Object context, Object request,
  3. Object response, Lifecycle lifecycle)
  4. throws FacesException;

来产生FacesContext对象,并且这是一个抽象方法,如何调用,则是JSF实现的事情了,并且FacesContextFactory会为每一个Request请求返回一个FacesContext对象。注意,这里用的是“返回”,而不是生成,是因为FacesContextFactory并不一定会为每一个请求生成一个新的FacesContext对象,FacesContext对象有一个release方法,这个方法负责释放FacesContext的资源,在调用这个方法之前,通过FacesContext.getCurrentInstance可以返回当前线程上的实例,这样实现FacesContext在某种程度上的重用和pool。
下面应该来看看在FacesServlet中如何调用FacesContextFactory来产生一个FacesContext对象了。
首先要产生一个FacesContextFactory对象,这是通过FacesServlet的init方法来实现的:
FacesServlet的init方法
  1. public void init(ServletConfig servletConfig) throws ServletException {
  2. // Save our ServletConfig instance
  3. this.servletConfig = servletConfig;
  4. // Acquire our FacesContextFactory instance
  5. try {
  6. facesContextFactory = (FacesContextFactory)
  7. FactoryFinder.getFactory
  8. (FactoryFinder.FACES_CONTEXT_FACTORY);
  9. } catch (FacesException e) {
  10. ResourceBundle rb = LOGGER.getResourceBundle();
  11. String msg = rb.getString("severe.webapp.facesservlet.init_failed");
  12. Throwable rootCause = (e.getCause() != null) ? e.getCause() : e;
  13. LOGGER.log(Level.SEVERE, msg, rootCause);
  14. throw new UnavailableException(msg);
  15. }
  16. // Acquire our Lifecycle instance
  17. try {
  18. LifecycleFactory lifecycleFactory = (LifecycleFactory)
  19. FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
  20. String lifecycleId ;
  21. // First look in the servlet init-param set
  22. if (null == (lifecycleId = servletConfig.getInitParameter(LIFECYCLE_ID_ATTR))) {
  23. // If not found, look in the context-param set
  24. lifecycleId = servletConfig.getServletContext().getInitParameter
  25. (LIFECYCLE_ID_ATTR);
  26. }
  27. if (lifecycleId == null) {
  28. lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;
  29. }
  30. lifecycle = lifecycleFactory.getLifecycle(lifecycleId);
  31. } catch (FacesException e) {
  32. Throwable rootCause = e.getCause();
  33. if (rootCause == null) {
  34. throw e;
  35. } else {
  36. throw new ServletException(e.getMessage(), rootCause);
  37. }
  38. }
  39. }

在这个init方法中,FacesServlet通过FactoryFinder对象来创建一个具体的Factory对象,这样就把创建Factory对象的工作给托管给其他的类了,同时这个FactoryFinder还可以创建其他的工厂类,因此可以说FactoryFinder是“工厂的工厂”,是专门创造工厂的类。通过 FactoryFinder.FACES_CONTEXT_FACTORY参数指明是创建FacesContextFactory,FactoryFinder就给创建出一个FacesContextFactory。
下面我们就来看看FactoryFinder是通过什么算法,来查找和创建JSF实现中的各个工厂类。
FactoryFinder通过实现标准的发现算法,可以查找所有在JSF API中指定的factory对象,这个算法是这样的:
1.如果 web应用的WEB-INF目录下 存在 JSF的configuration 文件,并且含有factory节点,而且这个factory节点中含有正在查找的factory对象的类名称,那么就加载这个类。
2.如果在ServletContext的初始化参数中有 javax.faces.CONFIG_FILES参数,并且这个参数值指定的配置文件中有factory节点,并且这个节点中含有目前正在查找的factory类名,那么就加载这个对象。
3.如果在ServletContext的资源目录下的Jar包中的 META-INF目录下含有JSF配置文件,并且正在查找的factory类名存在于factory节点中,则加载这个类。最晚加载的类优先。
4.如果META-INF/service/目录下有当前正在查找的类名称,会加载之。
5.如果上面的规则都没有匹配,则会使用JSF实现中的特定类。

这种算法的缺点就是每一个Web应用都会有一个自己的factory实例,不管这个JSF实现是包含在Web应用chengx程序之中还是在容器中作为一个共享库存在。

这个FactoryFinder还是蛮复杂的,以后有时间将另外撰文研究。
下面的事情就是LifecycleFactory的加载了,其加载过程不必多言。
LifecycleFactory对象加载后,会查找JSF中是否配置了javax.faces.LIFECYCLE_ID参数,根据这个参数加载lifecycleId,整个过程是这样的:
加载LifecycleFactory
  1. //AcquireourLifecycleinstance
  2. try{
  3. LifecycleFactorylifecycleFactory=(LifecycleFactory)
  4. FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
  5. StringlifecycleId;
  6. //Firstlookintheservletinit-paramset
  7. if(null==(lifecycleId=servletConfig.getInitParameter(LIFECYCLE_ID_ATTR))){
  8. //Ifnotfound,lookinthecontext-paramset
  9. lifecycleId=servletConfig.getServletContext().getInitParameter
  10. (LIFECYCLE_ID_ATTR);
  11. }
  12. if(lifecycleId==null){
  13. lifecycleId=LifecycleFactory.DEFAULT_LIFECYCLE;
  14. }
  15. lifecycle=lifecycleFactory.getLifecycle(lifecycleId);
  16. }catch(FacesExceptione){
  17. ThrowablerootCause=e.getCause();
  18. if(rootCause==null){
  19. throwe;
  20. }else{
  21. thrownewServletException(e.getMessage(),rootCause);
  22. }
  23. }


通过加载不同实现的LifecycleFactory对象,就可以允许加载不同的Lifecycle对象,这对于扩展JSF的功能是非常重要的,
当没有显示表明lifecycleId时,lifecycleFactory就会加载默认的lifecycleId,并根据lifecycleId加载Lifecycle对象
Lifecycle类负责JSF请求处理的全过程,主要是通过执行其中的execute方法和render方法实现的,FacesServlet的service方法很好的说明了这一点:

java 代码
  1. publicvoidservice(ServletRequestrequest,
  2. ServletResponseresponse)
  3. throwsIOException,ServletException{
  4. //Ifprefixmapped,thenensurerequestsfor/WEB-INFare
  5. //notprocessed.
  6. StringpathInfo=((HttpServletRequest)request).getPathInfo();
  7. if(pathInfo!=null){
  8. pathInfo=pathInfo.toUpperCase();
  9. if(pathInfo.startsWith("/WEB-INF/")
  10. ||pathInfo.equals("/WEB-INF")
  11. ||pathInfo.startsWith("/META-INF/")
  12. ||pathInfo.equals("/META-INF")){
  13. ((HttpServletResponse)response).
  14. sendError(HttpServletResponse.SC_NOT_FOUND);
  15. return;
  16. }
  17. }
  18. //AcquiretheFacesContextinstanceforthisrequest
  19. FacesContextcontext=facesContextFactory.getFacesContext
  20. (servletConfig.getServletContext(),request,response,lifecycle);
  21. //Executetherequestprocessinglifecycleforthisrequest
  22. try{
  23. lifecycle.execute(context);
  24. lifecycle.render(context);
  25. }catch(FacesExceptione){
  26. Throwablet=e.getCause();
  27. if(t==null){
  28. thrownewServletException(e.getMessage(),e);
  29. }else{
  30. if(tinstanceofServletException){
  31. throw((ServletException)t);
  32. }elseif(tinstanceofIOException){
  33. throw((IOException)t);
  34. }else{
  35. thrownewServletException(t.getMessage(),t);
  36. }
  37. }
  38. }
  39. finally{
  40. //ReleasetheFacesContextinstanceforthisrequest
  41. context.release();
  42. }
  43. }


好了,FacesServlet的源码我们就看到这里,下一篇中我们将深入研究Lifecycle对象的执行过程,在最后,就让我们用myFaces的FacesServlet实现来结束吧:

myfaces之FacesServlet:
  1. publicfinalclassFacesServletimplementsServlet{
  2. privatestaticfinalLoglog=LogFactory.getLog(FacesServlet.class);
  3. publicstaticfinalStringCONFIG_FILES_ATTR="javax.faces.CONFIG_FILES";
  4. publicstaticfinalStringLIFECYCLE_ID_ATTR="javax.faces.LIFECYCLE_ID";
  5. privatestaticfinalStringSERVLET_INFO="FacesServletoftheMyFacesAPIimplementation";
  6. privateServletConfig_servletConfig;
  7. privateFacesContextFactory_facesContextFactory;
  8. privateLifecycle_lifecycle;
  9. publicFacesServlet(){
  10. super();
  11. }
  12. publicvoiddestroy(){
  13. _servletConfig=null;
  14. _facesContextFactory=null;
  15. _lifecycle=null;
  16. if(log.isTraceEnabled())
  17. log.trace("destroy");
  18. }
  19. publicServletConfiggetServletConfig(){
  20. return_servletConfig;
  21. }
  22. publicStringgetServletInfo(){
  23. returnSERVLET_INFO;
  24. }
  25. privateStringgetLifecycleId(){
  26. StringlifecycleId=_servletConfig.getServletContext()
  27. .getInitParameter(LIFECYCLE_ID_ATTR);
  28. returnlifecycleId!=null?lifecycleId
  29. :LifecycleFactory.DEFAULT_LIFECYCLE;
  30. }
  31. publicvoidinit(ServletConfigservletConfig)throwsServletException{
  32. if(log.isTraceEnabled())
  33. log.trace("initbegin");
  34. _servletConfig=servletConfig;
  35. _facesContextFactory=(FacesContextFactory)FactoryFinder
  36. .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
  37. //TODO:null-checkforWeblogic,thattriestoinitializeServlet
  38. //beforeContextListener
  39. //Javadocsays:Lifecycleinstanceissharedacrossmultiple
  40. //simultaneousrequests,itmustbeimplementedinathread-safe
  41. //manner.
  42. //Sowecanacquireithereonce:
  43. LifecycleFactorylifecycleFactory=(LifecycleFactory)FactoryFinder
  44. .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
  45. _lifecycle=lifecycleFactory.getLifecycle(getLifecycleId());
  46. if(log.isTraceEnabled())
  47. log.trace("initend");
  48. }
  49. publicvoidservice(ServletRequestrequest,ServletResponseresponse)
  50. throwsIOException,ServletException{
  51. HttpServletRequesthttpRequest=((HttpServletRequest)request);
  52. StringpathInfo=httpRequest.getPathInfo();
  53. //ifitisaprefixmapping...
  54. if(pathInfo!=null
  55. &&(pathInfo.startsWith("/WEB-INF")||pathInfo
  56. .startsWith("/META-INF"))){
  57. StringBufferbuffer=newStringBuffer();
  58. buffer.append("Someoneistryingtoaccessasecureresource:"
  59. +pathInfo);
  60. buffer
  61. .append("/nremoteaddressis"
  62. +httpRequest.getRemoteAddr());
  63. buffer.append("/nremotehostis"+httpRequest.getRemoteHost());
  64. buffer.append("/nremoteuseris"+httpRequest.getRemoteUser());
  65. buffer.append("/nrequestURIis"+httpRequest.getRequestURI());
  66. log.warn(buffer.toString());
  67. //WhydoesRIreturna404andnota403,SC_FORBIDDEN?
  68. ((HttpServletResponse)response)
  69. .sendError(HttpServletResponse.SC_NOT_FOUND);
  70. return;
  71. }
  72. if(log.isTraceEnabled())
  73. log.trace("servicebegin");
  74. FacesContextfacesContext=_facesContextFactory.getFacesContext(
  75. _servletConfig.getServletContext(),request,response,
  76. _lifecycle);
  77. try{
  78. _lifecycle.execute(facesContext);
  79. _lifecycle.render(facesContext);
  80. }catch(Throwablee){
  81. if(einstanceofIOException){
  82. throw(IOException)e;
  83. }elseif(einstanceofServletException){
  84. throw(ServletException)e;
  85. }elseif(e.getMessage()!=null){
  86. thrownewServletException(e.getMessage(),e);
  87. }else{
  88. thrownewServletException(e);
  89. }
  90. }finally{
  91. facesContext.release();
  92. }
  93. if(log.isTraceEnabled())
  94. log.trace("serviceend");
  95. }
  96. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值