JSF @ViewScoped ведет себя как @ApplicationScoped

@ManagedBean не рекомендуется, поэтому я использовал рекомендуемый Замена CDI @Named с его javax.faces.view.ViewScoped аннотацией (не JSF javax.faces.bean.ViewScoped).

ПРОБЛЕМА

Bean ведет себя как @ApplicationScoped, то есть @PostConstruct вызывается при развертывании приложения, а затем никогда не вызывается снова, т.е. я не вижу @PostConstruct вызова при посещении / обновлении страницы.

Если я вернусь к аннотациям JSF, то есть bean-компонент @ManagedBean + javax.faces.bean.ViewScoped работает должным образом.

Я также пробовал @Named + org.omnifaces.cdi.ViewScoped, как указано в Как заменить @ManagedBean / @ViewScope на CDI в JSF 2.0 / 2.1, но результат был таким же, как и с javax.faces.view.ViewScoped (OmniFaces 2.6.2).

ДЛИННАЯ ИСТОРИЯ КРАТКАЯ

Это проблема интеграции JSF + Spring (4.3.1.RELEASE).


ПОДРОБНОСТИ

Приложение работает на Wildfly 11.0.0.

  • specTitle: JSR-000344: JavaServer (TM) Faces 2.2 API
  • specVersion: 2.2
  • specVendor: Oracle.
  • implTitle: JavaServer ™ Faces 2.2 API.
  • implVersion: 2.2.13 implVendor: JBoss от Red Hat

Фасоль

import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import java.io.Serializable;

@Named
@ViewScoped
public class TestBean implements Serializable {

    private String text;

    @PostConstruct
    private void onPostConstruct() { /* ... */ }
    public void init() { /* ... */ }
    public void onCommandButton() { /* ... */ }

    public String getText() { return text; }
    public void setText(String text) { this.text = text; }
    public String getOutput() { return text; }
}

Просмотр (PrimeFaces 6.0.18)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:p="http://primefaces.org/ui">

    <h:head>
    </h:head>

    <h:body>
        <f:event type="preRenderComponent" listener="#{testBean.init}"/>

        <h:form id="form">
            <p:inputText id="text" value="#{testBean.text}"/>
            <h:outputText id="output" value="#{testBean.output}" />
            <p:commandButton value="SUBMIT" 
                    action="#{testBean.onCommandButton}" 
                    update="output"/>
        </h:form>
    </h:body>
</html>

ИЗМЕНИТЬ

После предложения Kukeltje я просмотрел стек вызовов создания bean-компонента. Каким-то образом Spring управляет созданием фасоли. Это трассировка стека, если я генерирую исключение из конструктора TestBean.

Constructor threw exception; nested exception is java.lang.RuntimeException: TestBean
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1105)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1050)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:775)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:444)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:326)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
    at io.undertow.servlet.core.ApplicationListeners.contextInitialized(ApplicationListeners.java:187)
    at io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:205)
    at io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:174)
    at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:42)
    at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
    at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
    at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:239)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:99)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:81)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
    at java.util.concurrent.FutureTask.run(FutureTask.java)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
    at org.jboss.threads.JBossThread.run(JBossThread.java:320)

    Constructor threw exception; nested exception is java.lang.RuntimeException: TestBean
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:159)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1098)
    ... 33 more

Я проверил конфиги и обнаружил регистрацию пользовательской реализации Spring @Scope("view") (что-то похожее на this, но без обработки обратных вызовов), который используется в bean-компонентах проекта (@Controller + @Scope("view") - вероятно, плохой дизайн). Я думаю, что это не имеет ничего общего с данной проблемой, но для полноты картины applicationContext.xhtml выглядит так:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">

    <context:annotation-config/>

    <context:property-placeholder location="classpath*:application.properties" ignore-unresolvable="true"/>
    <context:property-placeholder location="classpath*:versionInfo.properties"/>

    <task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
    <task:executor id="myExecutor" pool-size="5"/>
    <task:scheduler id="myScheduler" pool-size="10"/>

    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
        <property name="scopes">
            <map>
                <entry key="view">
                    <bean class="path.to.custom.ViewScope"/>
                </entry>
            </map>
        </property>
    </bean>
</beans>

Вероятно, это корень проблемы:

@Configuration
@ComponentScan(basePackages = "path.to.beans.base.package")
@ImportResource({"/WEB-INF/hibernate-config.xml", "/WEB-INF/applicationContext.xml"})
@PropertySource(value={"classpath:application.properties"}, ignoreResourceNotFound = true)
@Import( SecurityConfig.class )
public class WebConfig {
    // nothing more...
}

Кажется, что CDI Spring конфликтует с CDI приложения. Есть ли у вас какие-нибудь предложения, что мне делать?


person matoni    schedule 15.05.2019    source источник
comment
Вы добавили @ViewScoped в свой компонент? У меня есть bean-компонент с @Named и @ViewScoped, и он работает должным образом.   -  person K.Nicholas    schedule 15.05.2019
comment
@ K.Nicholas Еще раз проверил - результат тот же.   -  person matoni    schedule 15.05.2019
comment
Пробовал и проблем не вижу. Метод onPostConstruct() вызывается при каждом запросе GET.   -  person K.Nicholas    schedule 15.05.2019
comment
Если вы установите точку останова в конструкторе и запустите в режиме отладки, откуда возникает вызов?   -  person Kukeltje    schedule 15.05.2019
comment
Да, а метаданные должны ли быть связаны с событием preRenderComponent? Никогда не использовал эту конструкцию   -  person Kukeltje    schedule 15.05.2019
comment
@Kukeltje Спасибо за ваше предложение. Это помогло мне определить причину проблемы, хотя я не знаю, как с ней справиться.   -  person matoni    schedule 15.05.2019
comment
Шаг 1: удалите тег omnifaces и добавьте тег spring (или отбросьте его, используя Spring все вместе ;-)) И 2: я понятия не имею, поддержка прекращается для меня здесь, так как я никогда не использовал и никогда не буду использовать Spring (чистый java-ee здесь) извините. Но на самом деле это тоже не проблема JSF, поскольку все области и аннотации предназначены для CDI, а не для JSF. И, черт возьми, Spring не знает / не знает CDI, он знает аннотации JSR-299 (@Named), но не знает области JSF (CDI) iirc. поэтому область просмотра JSF неизвестна, и она может вернуться к значению по умолчанию или что-то в этом роде ...   -  person Kukeltje    schedule 15.05.2019
comment
Даже если это для весенней загрузки, это может вам помочь: stackoverflow.com / questions / 46187725 /   -  person Xtreme Biker    schedule 16.05.2019
comment
@XtremeBiker Спасибо, проверю.   -  person matoni    schedule 16.05.2019