GenericApplicationContext无法强制转换为WebApplicationContext:Spring Web Flow

时间:2015-06-22 19:12:41

标签: java spring spring-mvc classcastexception spring-webflow-2

我试图在仅使用Java注释的Spring环境中仅使用Java注释来设置Spring Web Flow。但是,当我尝试访问我的流时,我得到以下异常

SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/forms] threw exception [Request processing failed; nested exception is org.springframework.webflow.execution.FlowExecutionException: Exception thrown in state 'referral' of flow 'test-flow'] with root cause
java.lang.ClassCastException: org.springframework.context.support.GenericApplicationContext cannot be cast to org.springframework.web.context.WebApplicationContext
at org.springframework.web.servlet.support.RequestContext.initContext(RequestContext.java:235)
at org.springframework.web.servlet.support.RequestContext.<init>(RequestContext.java:202)
at org.springframework.web.servlet.view.AbstractView.createRequestContext(AbstractView.java:316)
at org.springframework.web.servlet.view.AbstractView.createMergedOutputModel(AbstractView.java:296)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:265)
at org.springframework.webflow.mvc.servlet.ServletMvcView.doRender(ServletMvcView.java:55)
at org.springframework.webflow.mvc.view.AbstractMvcView.render(AbstractMvcView.java:196)
at org.springframework.webflow.engine.ViewState.render(ViewState.java:293)
at org.springframework.webflow.engine.ViewState.refresh(ViewState.java:242)
at org.springframework.webflow.engine.ViewState.resume(ViewState.java:220)
at org.springframework.webflow.engine.Flow.resume(Flow.java:537)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:259)
at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:169)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:228)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:957)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2476)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2465)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

我已经将错误的来源跟踪到RequestContext对象的实例化,该对象被传递给视图以便他们访问ApplicationContext(以及其他内容)。由于Spring能够调用我的流,因此我认为由于我的Web Flow文件中某处的配置错误而导致抛出此异常。我已经多次审核过它们,找不到任何看似明显的东西。您可以在下面找到我的Web Flow配置文件:

DispatcherConfig

@Configuration
@ComponentScan(basePackages = "----")
public class DispatcherConfig {

    @Autowired
    private FlowDefinitionRegistry flowDefinitionRegistry;
    @Autowired
    private FlowExecutor flowExecutor;
    @Autowired
    private AnnotationConfigWebApplicationContext appContext;

    @Bean
    public FlowHandlerAdapter flowHandlerAdapter()
    {
        FlowHandlerAdapter flowHandlerAdapter = new FlowHandlerAdapter();
        flowHandlerAdapter.setFlowExecutor(flowExecutor);
        return flowHandlerAdapter;
    }

    @Bean
    public FlowHandlerMapping flowHandlerMapping()
    {
        FlowHandlerMapping mapping = new FlowHandlerMapping();
        mapping.setFlowRegistry(flowDefinitionRegistry);
        mapping.setApplicationContext(appContext);
        mapping.setOrder(-1);
        return mapping;
    }
} 

WebFlowConfig

@Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {

    @Autowired
    private List<ViewResolver> viewResolvers;
    @Autowired
    private ConversionService conversionService;
    @Autowired
    private AnnotationConfigWebApplicationContext appContext;

    @Bean
    public FlowDefinitionRegistry flowRegistry()
    {
        return getFlowDefinitionRegistryBuilder()
            .setBasePath("/WEB-INF/flows")
            .addFlowLocationPattern("/**/*-flow.xml")
            .setFlowBuilderServices(getFlowBuilderServices())
            .build();
    }

    @Bean
    public FlowExecutor flowExecutor()
    {
        return getFlowExecutorBuilder(flowRegistry()).build();
    }

    public ExpressionParser getExpressionParser()
    {
        SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
        return new WebFlowSpringELExpressionParser(spelExpressionParser);
    }

    public FlowBuilderServices getFlowBuilderServices()
    {
        MvcViewFactoryCreator creator = new MvcViewFactoryCreator();
        creator.setViewResolvers(viewResolvers);
        creator.setApplicationContext(appContext);
        creator.setUseSpringBeanBinding(true);

        FlowBuilderServices services = new FlowBuilderServices();
        services.setViewFactoryCreator(creator);
        services.setConversionService(conversionService);
        services.setExpressionParser(getExpressionParser());
        return services;
    }
}

WebMvcConfig

@EnableWebMvc
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Bean
    public UrlBasedViewResolver velocityViewResolver()
    {
        UrlBasedViewResolver resolver = new VelocityViewResolver();
        resolver.setSuffix(".vm");
        resolver.setViewClass(VelocityView.class);
        return resolver;
    }

    @Bean
    public VelocityConfigurer velocityConfig()
    {
        VelocityConfigurer velocityConfigurer = new VelocityConfigurer();
        velocityConfigurer.setResourceLoaderPath("/templates/views/");
        return velocityConfigurer;
    }

    @Bean
    public List<ViewResolver> viewResolvers()
    {
        List<ViewResolver> resolvers = new ArrayList<>();

        resolvers.add(velocityViewResolver());

        return resolvers;
    }
}

我使用的视图技术是Velocity。 Spring Webflow版本2.4.1.RELEASE,Spring版本4.1.2.RELEASE,Java 1.8.0_45,Tomcat 7.0.62。

可能导致此异常的任何想法?

更新:已修复

感谢Roman提供答案。我制作了FlowBuilderServicesMvcViewFactoryCreator @Bean,这就摆脱了ClassCastException。但是,我的配置仍然存在一些问题。直到@Autowired之后,我的List<ViewResolver> viewResolvers MvcViewFactoryCreator才被实例化。因此,我必须创建一个为ViewResolver创建MvcViewFactoryCreator列表的方法。我正在研究如何使创作顺序正确,但现在这种方法有效。以下是我为使Web Flow正常运行而必须进行的更改

WebFlowConfig

@Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
    @Autowired
    ===
    -private List<ViewResolver> viewResolvers;
    ====
    +private UrlBasedViewResolver viewResolver
    ===

    ...

    @Autowired
    ===
    -private AnnotationConfigWebApplicationContext appContext;
    ===
    +private MvcViewFactoryCreator mvcViewFactoryCreator;
    ===

    ...

    +public List<ViewResolver> getViewResolvers()
    +{
    +    List<ViewResolver> resolvers = new ArrayList<>();
    +    resolvers.add(viewResolver);
    +
    +    return resolvers;
    +}

    ...

    +@Bean
    +public MvcViewFactoryCreator mvcViewFactoryCreator()
    +{
    +    MvcViewFactoryCreator creator = new MvcViewFactoryCreator();
    +    creator.setViewResolvers(getViewResolvers());
    +    creator.setUseSpringBeanBinding(true);
    +    return creator;
    +}

    @Bean
    public FlowBuilderServices flowBuilderServices()
    {
        ===
        -MvcViewFactoryCreator creator = new MvcViewFactoryCreator();
        -creator.setViewResolvers(viewResolvers);
        -creator.setApplicationContext(appContext);
        -creator.setUseSpringBeanBinding(true);
        ===

        FlowBuilderServices services = new FlowBuilderServices();
        ===
        -services.setViewFactoryCreator(creator);
        ===
        +services.setViewFactoryCreator(mvcViewFactoryCreator);
        ===
        services.setConversionService(conversionService);
        services.setExpressionParser(getExpressionParser());
        return services;
     }
}

1 个答案:

答案 0 :(得分:0)

FlowBuilderServices是一个Spring管理的bean,但在你的配置中它只是一个new实例。它喜欢ApplicationContextAwareInitializingBean,但只有在Spring管理下才会有效。

解决方案很简单:将@Bean放在getFlowBuilderServices()方法上。我认为您还应该MvcViewFactoryCreator单独@Bean而不要手动使用setApplicationContext()