我目前正在迁移大量旧代码到springboot应用程序。我们有JSF和SOAP服务,它们成功地迁移了。我面临着与WsConfigurerAdapter
相关的问题。如果我们启用EndpointInterceptor
,那么FacesServlet就不会正确地初始化并抛出以下的错误。
15:28:41.045 [http-nio-8080-exec-1] ERROR j.faces - Unable to obtain InjectionProvider from init time FacesContext. Does this container implement the Mojarra Injection SPI?
15:28:41.046 [http-nio-8080-exec-1] ERROR j.faces - Application was not properly initialized at startup, could not find Factory: javax.faces.context.FacesContextFactory. Attempting to find backup.
15:28:41.047 [http-nio-8080-exec-1] ERROR o.a.c.c.C.[.[.[/KSF] - Servlet.init() for servlet [FacesServlet] threw exception
java.lang.IllegalStateException: Could not find backup for factory javax.faces.context.FacesContextFactory.
at javax.faces.FactoryFinderInstance.getFactory(FactoryFinderInstance.java:541) ~[javax.faces-2.3.9.jar!/:2.3.9]
at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:292) ~[javax.faces-2.3.9.jar!/:2.3.9]
at javax.faces.webapp.FacesServlet.init(FacesServlet.java:374) ~[javax.faces-2.3.9.jar!/:2.3.9]
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1164) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:804) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:128) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.56.jar!/:?]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_222-4-redhat]
15:28:41.055 [http-nio-8080-exec-1] ERROR o.a.c.c.C.[.[.[.[FacesServlet] - Allocate exception for servlet [FacesServlet]
java.lang.IllegalStateException: Could not find backup for factory javax.faces.context.FacesContextFactory.
at javax.faces.FactoryFinderInstance.getFactory(FactoryFinderInstance.java:541) ~[javax.faces-2.3.9.jar!/:2.3.9]
at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:292) ~[javax.faces-2.3.9.jar!/:2.3.9]
at javax.faces.webapp.FacesServlet.init(FacesServlet.java:374) ~[javax.faces-2.3.9.jar!/:2.3.9]
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1164) ~[tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:804) ~[tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:128) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.56.jar!/:?]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_222-4-redhat]
Web服务配置代码
@EnableWs
@Configuration
public class MyWebServiceConfig {
@Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
ServletRegistrationBean<MessageDispatcherServlet> servletRegistrationBean = new ServletRegistrationBean<>(servlet, "/Services/*");
servletRegistrationBean.setName("MessageDispatcherServlet");
return servletRegistrationBean;
}
@Bean // this is causing JSF deployment issue
public WsConfigurerAdapter csfWsConfigurerAdapter() {
return new WsConfigurerAdapter() {
@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
if (interceptors == null) {
interceptors = new ArrayList<>();
}
MyPayloadValidatingInterceptor validatingInterceptor = new MyPayloadValidatingInterceptor();
validatingInterceptor.setValidateRequest(true);
validatingInterceptor.setValidateResponse(false);
validatingInterceptor.setSchemas(getSchemas());
try {
validatingInterceptor.afterPropertiesSet();
} catch (Exception e) {}
interceptors.add(validatingInterceptor);
}
};
}
}
我在JSF中使用质数面,所以下面列出了重要的依赖项
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<main.basedir>${project.basedir}/..</main.basedir>
<spring.boot.version>2.6.3</spring.boot.version>
<primefaces.version>5.3</primefaces.version>
<faces.version>2.3.9</faces.version>
</properties>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>${primefaces.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>${faces.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
version="2.2">
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
</faces-config>
Faces/JSF配置
@Configuration
public class MyJSFConfig implements ServletContextAware, WebMvcConfigurer {
@Bean
public ServletRegistrationBean<FacesServlet> servletRegistrationBean() {
ServletRegistrationBean<FacesServlet> servletRegistrationBean = new ServletRegistrationBean<>(
new FacesServlet(), "*.jsf", "*.xhtml");
servletRegistrationBean.setName("FacesServlet");
servletRegistrationBean.setLoadOnStartup(1);
return servletRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean<ConfigureListener> jsfConfigureListener() {
return new ServletListenerRegistrationBean<ConfigureListener>(new ConfigureListener());
}
@Override
public void setServletContext(ServletContext servletContext) {
// spring boot only works if this is set
// Iniciar el contexto de JSF
// http://stackoverflow.com/a/25509937/1199132
servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString());
servletContext.setInitParameter("javax.faces.FACELETS_SKIP_COMMENTS", Boolean.TRUE.toString());
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/my").setViewName("forward:/my/index.jsf");
}
我认为这是springboot的类加载问题。WsConfigurerAdapter使用DelegatingWsConfiguration,并根据WebServicesAutoConfiguration中缺少的bean进行配置。我们正在进行最新的springboot发行版
发布于 2022-02-01 21:11:24
它更多地与spring后bean处理的工作方式有关。仔细调试后发现,由于servlet上下文未初始化,Faces上下文未正确初始化,因此未调用ServletContextAware方法。
@Override
public void setServletContext(ServletContext servletContext) {
// spring boot only works if this is set
// Iniciar el contexto de JSF
// http://stackoverflow.com/a/25509937/1199132
servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString());
servletContext.setInitParameter("javax.faces.FACELETS_SKIP_COMMENTS", Boolean.TRUE.toString());
}
我更改为ServletContextInitializer,它在启动时被调用并正确地初始化所需的值。
下面的问题回答有助于识别。setServletContext not activating inside @Configuration file
完整工作示例项目如下所示:位置https://github.com/gaurangparmar/my-springboot-jsf
https://stackoverflow.com/questions/70933209
复制相似问题