了解 FacesContext 实例化细节

Understanding FacesContext instantiation details

Mojarra 2.2.12

这是接管 FacesContext 实例化的代码片段:

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

表达的很清楚。一旦我们收到请求,我们就会从中获取全局信息并使用它创建 FacesContext 实例。因此,实例是为每个请求创建的。但是获得 facesContextFactory 的实例在我看来要棘手得多。

// Acquire our FacesContextFactory instance
try {
    facesContextFactory = (FacesContextFactory)
        FactoryFinder.getFactory
        (FactoryFinder.FACES_CONTEXT_FACTORY);
} catch (FacesException e) {
    //others
}

哪里

String javax.faces.FactoryFinder.FACES_CONTEXT_FACTORY = "javax.faces.context.FacesContextFactory"

FactoryFinder 的 JavaDocs 描述了所谓的

standard discovery algorithm for all factory objects specified in the JavaServer Faces APIs.

这就是我困惑的地方。

现在,让我们考虑创建工厂实例的实际方法:javax.faces.FactoryFinderInstance#getFactory(String factoryName)

try {
      factoryOrList = factories.get(factoryName);
      if (!(factoryOrList instanceof List)) {
          return factoryOrList;
      }
} finally {
      lock.readLock().unlock();
}

factories字段初始化如下copyInjectionProviderFromFacesContext()

private void copyInjectionProviderFromFacesContext() {
    InjectionProvider injectionProvider = null;
    FacesContext context = FacesContext.getCurrentInstance(); //USE FACES CONTEXT!!!!!
    if (null != context) {
        injectionProvider = (InjectionProvider) context.getAttributes().get("com.sun.faces.config.ConfigManager_INJECTION_PROVIDER_TASK");
    }
    if (null != injectionProvider) {
        factories.put(INJECTION_PROVIDER_KEY, injectionProvider);
    } else {
        if (LOGGER.isLoggable(Level.SEVERE)) {
            LOGGER.log(Level.SEVERE, "Unable to obtain InjectionProvider from init time FacesContext. Does this container implement the Mojarra Injection SPI?");
        }
    }
}

因此,创建使用 FacesContext 实例,但工厂本身用于创建 FacesContext。你不能解释一下那个周期吗?

有一个特殊的“init FacesContext”,它在 servlet 容器初始化期间可用,确保在 JSF 初始化期间至少有 "a" FacesContext。这个特殊的 "init FacesContext" 有很多 empty/null/default 属性,尤其是那些依赖于 HTTP servlet request/response 的属性,但是应用程序和配置相关的属性,例如通过 FacesContext#getApplication() 可用的属性已经可用基于 a.o。 faces-config.xml.

对于 Mojarra,此 "init FacesContext" 是在 webapp 启动期间运行的 created in a.o. the com.sun.faces.config.FacesInitializer, a ServletContainerInitializer 实现。在那一刻,工厂被创建。