欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

JSF 源代码赏析之FacesServlet

发布时间:2025/3/16 56 豆豆
生活随笔 收集整理的这篇文章主要介绍了 JSF 源代码赏析之FacesServlet 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

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

文件头部的注释
  • /**
  • *

    FacesServlet is a servlet that manages the request

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

     

  • */
  • 头部注释说的很明白,管理请求的处理周期。至于怎么管理,下面先来看一看到底声明了什么变量
    变量
  • public static final String CONFIG_FILES_ATTR =
  • "javax.faces.CONFIG_FILES";
  • public static final String LIFECYCLE_ID_ATTR =
  • "javax.faces.LIFECYCLE_ID";
  • private static final Logger LOGGER =
  • Logger.getLogger("javax.faces.webapp", "javax.faces.LogStrings");
  • private FacesContextFactory facesContextFactory = null;
  • private Lifecycle lifecycle = null;
  • 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
  • public abstract FacesContext getFacesContext
  • (Object context, Object request,
  • Object response, Lifecycle lifecycle)
  • throws FacesException;

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

  • 在这个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
  • // Acquire our Lifecycle instance  
  •        try {  
  •            LifecycleFactory lifecycleFactory = (LifecycleFactory)  
  •                FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);  
  •            String lifecycleId ;  
  •   
  •            // First look in the servlet init-param set  
  •            if (null == (lifecycleId = servletConfig.getInitParameter(LIFECYCLE_ID_ATTR))) {  
  •                // If not found, look in the context-param set   
  •                lifecycleId = servletConfig.getServletContext().getInitParameter  
  •                    (LIFECYCLE_ID_ATTR);  
  •            }  
  •   
  •            if (lifecycleId == null) {  
  •                lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;  
  •            }  
  •            lifecycle = lifecycleFactory.getLifecycle(lifecycleId);  
  •        } catch (FacesException e) {  
  •            Throwable rootCause = e.getCause();  
  •            if (rootCause == null) {  
  •                throw e;  
  •            } else {  
  •                throw new ServletException(e.getMessage(), rootCause);  
  •            }  
  •        }  

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

    java 代码
  • public void service(ServletRequest request,   
  •                        ServletResponse response)   
  •        throws IOException, ServletException {   
  •   
  •        // If prefix mapped, then ensure requests for /WEB-INF are   
  •        // not processed.   
  •        String pathInfo = ((HttpServletRequest) request).getPathInfo();   
  •        if (pathInfo != null) {   
  •            pathInfo = pathInfo.toUpperCase();   
  •            if (pathInfo.startsWith("/WEB-INF/")   
  •                || pathInfo.equals("/WEB-INF")   
  •                || pathInfo.startsWith("/META-INF/")   
  •                || pathInfo.equals("/META-INF")) {   
  •                ((HttpServletResponse) response).   
  •                      sendError(HttpServletResponse.SC_NOT_FOUND);   
  •                return;   
  •            }   
  •        }       
  •           
  •        // Acquire the FacesContext instance for this request   
  •        FacesContext context = facesContextFactory.getFacesContext   
  •            (servletConfig.getServletContext(), request, response, lifecycle);   
  •   
  •        // Execute the request processing lifecycle for this request   
  •        try {   
  •            lifecycle.execute(context);   
  •            lifecycle.render(context);   
  •        } catch (FacesException e) {   
  •            Throwable t = e.getCause();   
  •            if (t == null) {   
  •                throw new ServletException(e.getMessage(), e);   
  •            } else {   
  •                if (t instanceof ServletException) {   
  •                    throw ((ServletException) t);   
  •                } else if (t instanceof IOException) {   
  •                    throw ((IOException) t);   
  •                } else {   
  •                    throw new ServletException(t.getMessage(), t);   
  •                }   
  •            }   
  •        }   
  •        finally {   
  •            // Release the FacesContext instance for this request   
  •            context.release();   
  •        }   
  •   
  •    }   

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

    myfaces之FacesServlet:
  • public final class FacesServlet implements Servlet {   
  •     private static final Log log = LogFactory.getLog(FacesServlet.class);   
  •     public static final String CONFIG_FILES_ATTR = "javax.faces.CONFIG_FILES";   
  •     public static final String LIFECYCLE_ID_ATTR = "javax.faces.LIFECYCLE_ID";   
  •   
  •     private static final String SERVLET_INFO = "FacesServlet of the MyFaces API implementation";   
  •     private ServletConfig _servletConfig;   
  •     private FacesContextFactory _facesContextFactory;   
  •     private Lifecycle _lifecycle;   
  •   
  •     public FacesServlet() {   
  •         super();   
  •     }   
  •   
  •     public void destroy() {   
  •         _servletConfig = null;   
  •         _facesContextFactory = null;   
  •         _lifecycle = null;   
  •         if (log.isTraceEnabled())   
  •             log.trace("destroy");   
  •     }   
  •   
  •     public ServletConfig getServletConfig() {   
  •         return _servletConfig;   
  •     }   
  •   
  •     public String getServletInfo() {   
  •         return SERVLET_INFO;   
  •     }   
  •   
  •     private String getLifecycleId() {   
  •         String lifecycleId = _servletConfig.getServletContext()   
  •                 .getInitParameter(LIFECYCLE_ID_ATTR);   
  •         return lifecycleId != null ? lifecycleId   
  •                 : LifecycleFactory.DEFAULT_LIFECYCLE;   
  •     }   
  •   
  •     public void init(ServletConfig servletConfig) throws ServletException {   
  •         if (log.isTraceEnabled())   
  •             log.trace("init begin");   
  •         _servletConfig = servletConfig;   
  •         _facesContextFactory = (FacesContextFactory) FactoryFinder   
  •                 .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);   
  •         // TODO: null-check for Weblogic, that tries to initialize Servlet   
  •         // before ContextListener   
  •   
  •         // Javadoc says: Lifecycle instance is shared across multiple   
  •         // simultaneous requests, it must be implemented in a thread-safe   
  •         // manner.   
  •         // So we can acquire it here once:   
  •         LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder   
  •                 .getFactory(FactoryFinder.LIFECYCLE_FACTORY);   
  •         _lifecycle = lifecycleFactory.getLifecycle(getLifecycleId());   
  •         if (log.isTraceEnabled())   
  •             log.trace("init end");   
  •     }   
  •   
  •     public void service(ServletRequest request, ServletResponse response)   
  •             throws IOException, ServletException {   
  •   
  •         HttpServletRequest httpRequest = ((HttpServletRequest) request);   
  •         String pathInfo = httpRequest.getPathInfo();   
  •   
  •         // if it is a prefix mapping ...   
  •         if (pathInfo != null  
  •                 && (pathInfo.startsWith("/WEB-INF") || pathInfo   
  •                         .startsWith("/META-INF"))) {   
  •             StringBuffer buffer = new StringBuffer();   
  •   
  •             buffer.append(" Someone is trying to access a secure resource : "  
  •                     + pathInfo);   
  •             buffer   
  •                     .append("/n remote address is "  
  •                             + httpRequest.getRemoteAddr());   
  •             buffer.append("/n remote host is " + httpRequest.getRemoteHost());   
  •             buffer.append("/n remote user is " + httpRequest.getRemoteUser());   
  •             buffer.append("/n request URI is " + httpRequest.getRequestURI());   
  •   
  •             log.warn(buffer.toString());   
  •   
  •             // Why does RI return a 404 and not a 403, SC_FORBIDDEN ?   
  •   
  •             ((HttpServletResponse) response)   
  •                     .sendError(HttpServletResponse.SC_NOT_FOUND);   
  •             return;   
  •         }   
  •   
  •         if (log.isTraceEnabled())   
  •             log.trace("service begin");   
  •         FacesContext facesContext = _facesContextFactory.getFacesContext(   
  •                 _servletConfig.getServletContext(), request, response,   
  •                 _lifecycle);   
  •         try {   
  •             _lifecycle.execute(facesContext);   
  •             _lifecycle.render(facesContext);   
  •         } catch (Throwable e) {   
  •             if (e instanceof IOException) {   
  •                 throw (IOException) e;   
  •             } else if (e instanceof ServletException) {   
  •                 throw (ServletException) e;   
  •             } else if (e.getMessage() != null) {   
  •                 throw new ServletException(e.getMessage(), e);   
  •             } else {   
  •                 throw new ServletException(e);   
  •             }   
  •         } finally {   
  •             facesContext.release();   
  •         }   
  •         if (log.isTraceEnabled())   
  •             log.trace("service end");   
  •     }   
  • }   
  • 总结

    以上是生活随笔为你收集整理的JSF 源代码赏析之FacesServlet的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。