【问题标题】:Spring Boot with JSF; Could not find backup for factory javax.faces.context.FacesContextFactory带有 JSF 的 Spring Boot;找不到工厂 javax.faces.context.FacesContextFactory 的备份
【发布时间】:2014-10-18 06:05:36
【问题描述】:

我在使用 Spring Boot 和 JSF 时遇到了一些问题。 servlet 似乎可以正确启动,但是当我尝试访问资源时出现以下异常

java.lang.IllegalStateException: Could not find backup for factory javax.faces.context.FacesContextFactory. 
    at javax.faces.FactoryFinder$FactoryManager.getFactory(FactoryFinder.java:1011)
    at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:343)
    at javax.faces.webapp.FacesServlet.init(FacesServlet.java:302)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1284)
    at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:884)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:134)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:683)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1720)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1679)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:724)

我的Application类如下

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    @Bean
    public FacesServlet facesServlet() {
        return new FacesServlet();
    }

    @Bean
    public ServletRegistrationBean facesServletRegistration() {
        ServletRegistrationBean registration = new ServletRegistrationBean(
            facesServlet(), "*.xhtml");
        registration.setName("Christmas");
        return registration;
    }

    @Bean
    public ServletListenerRegistrationBean<ConfigureListener> jsfConfigureListener() {
        return new ServletListenerRegistrationBean<ConfigureListener>(
            new ConfigureListener());
    }
}

我没有web.xml或者faces-config.xml,我的pom.xml如下

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.x.y.z</groupId>
    <artifactId>project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.5.RELEASE</version>
    </parent>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>primefaces</artifactId>
            <version>5.0</version>
        </dependency>

        <!-- JSF 2 -->
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.1.11</version>
        </dependency>

        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>2.1.11</version>
        </dependency>
    </dependencies>

</project>

我怀疑与 jsf api 相关的依赖项中存在一些冲突,但我似乎无法弄清楚在哪里。任何有关解决此问题的帮助将不胜感激。

【问题讨论】:

  • 我已经删除了 servlet 依赖项,但我仍然遇到同样的问题。我的运行时类路径以什么方式一团糟?我该如何清洁它?
  • 谢谢,我相信我已经按照链接建议的方式配置了我的 pom。我对 jsf-api 和 jsf-impl 有 2 个依赖项。我什至尝试使 jsf-api 依赖项具有“提供”范围,但问题仍然存在。

标签: maven jsf jsf-2 spring-boot


【解决方案1】:

要让 JSF 在没有 web.xmlfaces-config.xml 的情况下在 Spring Boot 上工作,您需要通过 ServletContext 上的 init 参数强制它加载其配置文件。一个简单的方法是实现ServletContextAware

public class Application implements ServletContextAware {

    // ...

    @Override
    public void setServletContext(ServletContext servletContext) {
        servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString());           
    }
}

JSF 的ConfigureListener 也依赖于 JSP,因此您需要在 pom 中添加对 Jasper 的依赖:

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
</dependency>

它与您的问题没有直接关系,但您不需要将FacesServlet 声明为bean。 ServletRegistrationBean 就足够了。

这使Application.java 看起来如下:

import javax.faces.webapp.FacesServlet;
import javax.servlet.ServletContext;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.embedded.ServletListenerRegistrationBean;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.ServletContextAware;

import com.sun.faces.config.ConfigureListener;

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application implements ServletContextAware {

    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }

    @Bean
    public ServletRegistrationBean facesServletRegistration() {
        ServletRegistrationBean registration = new ServletRegistrationBean(
            new FacesServlet(), "*.xhtml");
        registration.setLoadOnStartup(1);
        return registration;
    }

    @Bean
    public ServletListenerRegistrationBean<ConfigureListener> jsfConfigureListener() {
        return new ServletListenerRegistrationBean<ConfigureListener>(
            new ConfigureListener());
    }

    @Override
    public void setServletContext(ServletContext servletContext) {
        servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString());       
    }
}

【讨论】:

  • 是的,我做到了。 OP 使用 Spring Boot 和嵌入式 servlet 容器,即初始化 Tomcat 的是 Spring Boot。至关重要的是,setServletContext 被调用 before ConfigureListener 被驱动,它允许 init 参数生效。
  • 没有 [@EnableAutoConfiguration] 注释的 [Application] 应该如何?我使用了没有此注释的解决方案,它仍然需要两个文件 [web.xml] 和 [faces-config.xml]。看到这个帖子stackoverflow.com/questions/22544214/…
  • forceLoadConfiguration 参数确实解决了我的项目(打包的jar)中的“工厂备份”异常的问题,但是现在它没有找到.xhtml 文件并返回404 错误。以前,在我没有 forceLoadConfiguration 的项目中,我一切都在运行“mvn spring-boot:run”,但是在打包它并在具有依赖项的独立 jar 中运行它时失败了。
  • 忽略我发布的内容,我只需将包装从 jar 更改为 war,它现在可以完美运行了。
  • @Cenobyte321:你到底做了什么?我遇到了同样的问题:将应用程序及其依赖项打包在一个唯一的 jar 中,执行这个 jar 并遇到错误 [java.lang.IllegalStateException: 找不到工厂 javax.faces.context.FacesContextFactory 的备份。] 运行时进入 Netbeans IDE(不打包),应用程序工作。
【解决方案2】:

可能你忘记添加监听器 com.sun.faces.config.ConfigureListener.class :

  @Bean
    public ServletContextInitializer servletContextInitializer() {

        return sc -> {
            ***sc.addListener(com.sun.faces.config.ConfigureListener.class);***
            sc.setInitParameter("com.sun.faces.expressionFactory", "com.sun.el.ExpressionFactoryImpl");
            sc.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString());
            sc.setInitParameter("facelets.DEVELOPMENT", Boolean.TRUE.toString());
            sc.setInitParameter("javax.faces.DEFAULT_SUFFIX", ".xhtml");
            sc.setInitParameter("javax.faces.FACELETS_LIBRARIES", "springsecurity.taglib.xml");
            sc.setInitParameter("javax.faces.FACELETS_REFRESH_PERIOD", "1");
            sc.setInitParameter("javax.faces.FACELETS_SKIP_COMMENTS", Boolean.TRUE.toString());
            sc.setInitParameter("javax.faces.PARTIAL_STATE_SAVING_METHOD", Boolean.TRUE.toString());
            sc.setInitParameter("javax.faces.PROJECT_STAGE", "Development");
            sc.setInitParameter("javax.faces.STATE_SAVING_METHOD", "server");
            sc.setInitParameter("primefaces.CLIENT_SIDE_VALIDATION", Boolean.TRUE.toString());
            sc.setInitParameter("primefaces.FONT_AWESOME", Boolean.TRUE.toString());
            sc.setInitParameter("primefaces.THEME", "Omega");
        };
    }

【讨论】:

    猜你喜欢
    • 2014-09-07
    • 1970-01-01
    • 2015-07-03
    • 2018-08-13
    • 2011-12-14
    • 2012-01-16
    • 2012-03-05
    • 1970-01-01
    相关资源
    最近更新 更多