`

JSF 源代码赏析之FacesServlet

    博客分类:
  • JSF
阅读更多
学习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. // Acquire our Lifecycle instance  
  2.        try {  
  3.            LifecycleFactory lifecycleFactory = (LifecycleFactory)  
  4.                FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);  
  5.            String lifecycleId ;  
  6.   
  7.            // First look in the servlet init-param set  
  8.            if (null == (lifecycleId = servletConfig.getInitParameter(LIFECYCLE_ID_ATTR))) {  
  9.                // If not found, look in the context-param set   
  10.                lifecycleId = servletConfig.getServletContext().getInitParameter  
  11.                    (LIFECYCLE_ID_ATTR);  
  12.            }  
  13.   
  14.            if (lifecycleId == null) {  
  15.                lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;  
  16.            }  
  17.            lifecycle = lifecycleFactory.getLifecycle(lifecycleId);  
  18.        } catch (FacesException e) {  
  19.            Throwable rootCause = e.getCause();  
  20.            if (rootCause == null) {  
  21.                throw e;  
  22.            } else {  
  23.                throw new ServletException(e.getMessage(), rootCause);  
  24.            }  
  25.        }  


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

java 代码
  1. public void service(ServletRequest request,   
  2.                        ServletResponse response)   
  3.        throws IOException, ServletException {   
  4.   
  5.        // If prefix mapped, then ensure requests for /WEB-INF are   
  6.        // not processed.   
  7.        String pathInfo = ((HttpServletRequest) request).getPathInfo();   
  8.        if (pathInfo != null) {   
  9.            pathInfo = pathInfo.toUpperCase();   
  10.            if (pathInfo.startsWith("/WEB-INF/")   
  11.                || pathInfo.equals("/WEB-INF")   
  12.                || pathInfo.startsWith("/META-INF/")   
  13.                || pathInfo.equals("/META-INF")) {   
  14.                ((HttpServletResponse) response).   
  15.                      sendError(HttpServletResponse.SC_NOT_FOUND);   
  16.                return;   
  17.            }   
  18.        }       
  19.           
  20.        // Acquire the FacesContext instance for this request   
  21.        FacesContext context = facesContextFactory.getFacesContext   
  22.            (servletConfig.getServletContext(), request, response, lifecycle);   
  23.   
  24.        // Execute the request processing lifecycle for this request   
  25.        try {   
  26.            lifecycle.execute(context);   
  27.            lifecycle.render(context);   
  28.        } catch (FacesException e) {   
  29.            Throwable t = e.getCause();   
  30.            if (t == null) {   
  31.                throw new ServletException(e.getMessage(), e);   
  32.            } else {   
  33.                if (t instanceof ServletException) {   
  34.                    throw ((ServletException) t);   
  35.                } else if (t instanceof IOException) {   
  36.                    throw ((IOException) t);   
  37.                } else {   
  38.                    throw new ServletException(t.getMessage(), t);   
  39.                }   
  40.            }   
  41.        }   
  42.        finally {   
  43.            // Release the FacesContext instance for this request   
  44.            context.release();   
  45.        }   
  46.   
  47.    }   


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

myfaces之FacesServlet:
  1. public final class FacesServlet implements Servlet {   
  2.     private static final Log log = LogFactory.getLog(FacesServlet.class);   
  3.     public static final String CONFIG_FILES_ATTR = "javax.faces.CONFIG_FILES";   
  4.     public static final String LIFECYCLE_ID_ATTR = "javax.faces.LIFECYCLE_ID";   
  5.   
  6.     private static final String SERVLET_INFO = "FacesServlet of the MyFaces API implementation";   
  7.     private ServletConfig _servletConfig;   
  8.     private FacesContextFactory _facesContextFactory;   
  9.     private Lifecycle _lifecycle;   
  10.   
  11.     public FacesServlet() {   
  12.         super();   
  13.     }   
  14.   
  15.     public void destroy() {   
  16.         _servletConfig = null;   
  17.         _facesContextFactory = null;   
  18.         _lifecycle = null;   
  19.         if (log.isTraceEnabled())   
  20.             log.trace("destroy");   
  21.     }   
  22.   
  23.     public ServletConfig getServletConfig() {   
  24.         return _servletConfig;   
  25.     }   
  26.   
  27.     public String getServletInfo() {   
  28.         return SERVLET_INFO;   
  29.     }   
  30.   
  31.     private String getLifecycleId() {   
  32.         String lifecycleId = _servletConfig.getServletContext()   
  33.                 .getInitParameter(LIFECYCLE_ID_ATTR);   
  34.         return lifecycleId != null ? lifecycleId   
  35.                 : LifecycleFactory.DEFAULT_LIFECYCLE;   
  36.     }   
  37.   
  38.     public void init(ServletConfig servletConfig) throws ServletException {   
  39.         if (log.isTraceEnabled())   
  40.             log.trace("init begin");   
  41.         _servletConfig = servletConfig;   
  42.         _facesContextFactory = (FacesContextFactory) FactoryFinder   
  43.                 .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);   
  44.         // TODO: null-check for Weblogic, that tries to initialize Servlet   
  45.         // before ContextListener   
  46.   
  47.         // Javadoc says: Lifecycle instance is shared across multiple   
  48.         // simultaneous requests, it must be implemented in a thread-safe   
  49.         // manner.   
  50.         // So we can acquire it here once:   
  51.         LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder   
  52.                 .getFactory(FactoryFinder.LIFECYCLE_FACTORY);   
  53.         _lifecycle = lifecycleFactory.getLifecycle(getLifecycleId());   
  54.         if (log.isTraceEnabled())   
  55.             log.trace("init end");   
  56.     }   
  57.   
  58.     public void service(ServletRequest request, ServletResponse response)   
  59.             throws IOException, ServletException {   
  60.   
  61.         HttpServletRequest httpRequest = ((HttpServletRequest) request);   
  62.         String pathInfo = httpRequest.getPathInfo();   
  63.   
  64.         // if it is a prefix mapping ...   
  65.         if (pathInfo != null  
  66.                 && (pathInfo.startsWith("/WEB-INF") || pathInfo   
  67.                         .startsWith("/META-INF"))) {   
  68.             StringBuffer buffer = new StringBuffer();   
  69.   
  70.             buffer.append(" Someone is trying to access a secure resource : "  
  71.                     + pathInfo);   
  72.             buffer   
  73.                     .append("\n remote address is "  
  74.                             + httpRequest.getRemoteAddr());   
  75.             buffer.append("\n remote host is " + httpRequest.getRemoteHost());   
  76.             buffer.append("\n remote user is " + httpRequest.getRemoteUser());   
  77.             buffer.append("\n request URI is " + httpRequest.getRequestURI());   
  78.   
  79.             log.warn(buffer.toString());   
  80.   
  81.             // Why does RI return a 404 and not a 403, SC_FORBIDDEN ?   
  82.   
  83.             ((HttpServletResponse) response)   
  84.                     .sendError(HttpServletResponse.SC_NOT_FOUND);   
  85.             return;   
  86.         }   
  87.   
  88.         if (log.isTraceEnabled())   
  89.             log.trace("service begin");   
  90.         FacesContext facesContext = _facesContextFactory.getFacesContext(   
  91.                 _servletConfig.getServletContext(), request, response,   
  92.                 _lifecycle);   
  93.         try {   
  94.             _lifecycle.execute(facesContext);   
  95.             _lifecycle.render(facesContext);   
  96.         } catch (Throwable e) {   
  97.             if (e instanceof IOException) {   
  98.                 throw (IOException) e;   
  99.             } else if (e instanceof ServletException) {   
  100.                 throw (ServletException) e;   
  101.             } else if (e.getMessage() != null) {   
  102.                 throw new ServletException(e.getMessage(), e);   
  103.             } else {   
  104.                 throw new ServletException(e);   
  105.             }   
  106.         } finally {   
  107.             facesContext.release();   
  108.         }   
  109.         if (log.isTraceEnabled())   
  110.             log.trace("service end");   
  111.     }   
  112. }   







分享到:
评论
7 楼 will-vip 2009-02-01  
看了一些思想,mark下
6 楼 thc 2008-09-13  
谢谢你!写的很好!
5 楼 keypoint 2008-04-05  
主人太立了,希望看到你更多源码赏析系列!!!
4 楼 bochuxt 2008-02-20  
谢谢你,我已经打印你的文章拜读,再次感谢你的辛勤劳动.希望多出好文章.
3 楼 hintcnuie 2008-01-31  
这个源代码都是可以download下来的啊,Sun的,myFaces的,都可以
2 楼 hspeed 2008-01-13  
晕死,找到下源码的地方了。。。。。。。。
https://javaserverfaces.dev.java.net/servlets/ProjectDocumentList?expandFolder=6512&folderID=7028

有需要的朋友去下吧,研究出成果记得分享哦,哈
jsf-1.2_04-b07-FCS-src.zip
1 楼 hspeed 2008-01-11  
强人啊,请问你这源码是哪来的啊,不会是反编译的吧
希望看到你更多的研究成果啊

相关推荐

    JavaEE源代码 jsf-api

    JavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-apiJavaEE源代码 jsf-...

    JavaEE源代码 jsf-impl

    JavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源代码 jsf-implJavaEE源...

    Jsf 项目源代码

    在"Jsf 项目源代码"这个压缩包中,我们可以推测这包含了一个基于JSF 2.0版本的项目。JSF 2.0是该框架的一个重要版本,引入了许多增强功能,例如面部刷新(Facelet)、视图状态管理、自定义标签改进以及请求处理的...

    JSF上传 JSF大文件上传 JSF上传代码 JSF上传源代码

    项目的源代码中应该包含了上述所有部分,提供了一个完整的JSF大文件上传解决方案。对于希望学习或改进自己JSF文件上传功能的开发者来说,这是一个宝贵的资源。通过深入研究源代码,可以了解到如何处理大文件、如何...

    jsf 源代码

    JSF的组件模型是其核心特性之一。它提供了大量的UI组件,如按钮、输入框、表格等,开发者可以通过XML(在JSF中是Facelets或JSP)来声明这些组件。每个组件都有自己的生命周期和属性,可以与后端的数据模型绑定,实现...

    JSF2.0源代码

    **JSF 2.0 源代码详解** JavaServer Faces (JSF) 是一个用于构建Web用户界面的Java框架,由Sun Microsystems(现已被Oracle收购)开发并维护。JSF 2.0是该框架的一个重要版本,它带来了许多改进和新特性,提升了...

    jsf1.2源代码下载

    **JSF 1.2 源代码详解** JavaServer Faces (JSF) 是一个用于构建用户界面的Java EE框架,它提供了一种组件化的方式来创建Web应用程序。JSF 1.2是该框架的一个重要版本,发布于2007年,带来了许多增强功能和改进,...

    Core JSF源代码

    **标题“Core JSF源代码”** 提供的源码可能是书中示例代码的集合,这些代码可以帮助读者更直观地理解书中讲解的概念和技术。通过分析和运行这些源码,开发者可以更好地学习JSF的实践操作和工作原理。 **描述中的...

    JSF1.2.07版源代码

    **JSF 1.2.07 源代码详解** JavaServer Faces (JSF) 是Java平台上用于构建用户界面的官方标准框架,它提供了一种声明式的方式来创建Web应用程序。JSF 1.2是该框架的一个重要版本,引入了许多增强功能和改进,为...

    JSF实例源代码下载

    在这个"JSF实例源代码下载"中,我们有机会深入学习和理解JSF的工作原理及其应用。 1. **JSF框架概述**:JSF设计的主要目标是简化服务器端的Web开发,通过提供可重用的UI组件和事件处理机制。JSF生命周期包括六步:...

    JSF入门实例 源代码

    这个"JSF入门实例 源代码"是专门为初学者设计的,帮助他们快速理解并掌握JSF的基本概念和用法。下面我们将深入探讨JSF的核心特性、工作原理以及如何通过给定的实例进行学习。 1. JSF概述: JSF是一种官方支持的...

    JSF工程实例源代码

    **JSF(JavaServer Faces)** 是Java平台上的一种用于...通过研究源代码,你可以了解如何将用户界面与后端服务集成,以及如何处理复杂的文件I/O和数据库操作。此外,这个实例也可以作为你自定义文件管理系统的起点。

    JSF IN ACTION 源代码

    **JSF IN ACTION 源代码详解** "JSF IN ACTION 源代码" 是一本深入探讨JavaServer Faces(JSF)技术的书籍的配套源码。这本书籍旨在帮助开发者全面理解JSF框架,通过实践代码来提升技能。源代码的提供意味着读者...

    完整的jsf博客源代码

    在本例中,我们有一个完整的JSF博客源代码,该源码使用了Apache Derby数据库,特别适合初学者用来学习JSF的基础知识和实际应用。** **1. JSF框架详解** JSF的核心概念是组件模型,它允许开发者通过拖放UI组件来构建...

    richface and jsf 源代码

    richface,jsf源码。相当不错的资料。特别是richface.里面有不错的例子。放到tomcat下可以直接运行啊。

    JSF编程 光盘 源代码 2

    本资源包含的是《JSF编程》一书第二章的配套源代码,这将有助于读者深入理解JSF的工作原理和实践应用。 在JSF中,一个关键概念是UI组件。这些组件可以是简单的HTML元素,如按钮和文本输入,也可以是复杂的自定义...

    jsf in Action源代码(6-10章).rar

    《JSF in Action》是一本深入探讨JavaServer Faces(JSF)框架的权威书籍,而提供的源代码(6-10章)则是该书实践部分的重要组成部分。JSF是Java平台上的一个用于构建Web应用程序的组件模型框架,它极大地简化了用户...

    jsf完全参考手册源代码

    这个“JSF完全参考手册源代码”很可能包含了详细的示例和实现,帮助开发者深入理解JSF的工作原理以及如何在实际项目中应用。 在描述中提到的“jsf完全参考手册中的源代码”,暗示了这是一个学习资源,它可能包括了...

    JSF(java server faces)开源框架的源代码

    在你所拥有的"JSF(java server faces)开源框架的源代码"压缩包中,包含的是JSF 1.1版本的源码,这对于深入理解和学习这个框架有着重要的价值。 首先,让我们来看看JSF框架的基础结构和主要组成部分: 1. **组件...

    JSF编程 光盘 源代码 3

    **JSF编程 光盘 源代码 3** JavaServer Faces(JSF)是一种用于构建Web用户界面的Java EE框架,它简化了创建复杂的、数据驱动的Web应用程序的过程。这个压缩包文件“JSF编程 光盘 源代码 3”提供了《JSF编程》一书...

Global site tag (gtag.js) - Google Analytics