@PostConstruct 方法为同一个请求调用了两次

Posted

技术标签:

【中文标题】@PostConstruct 方法为同一个请求调用了两次【英文标题】:@PostConstruct method called twice for the same request 【发布时间】:2012-02-23 01:53:54 【问题描述】:

我将 JSF 2.0 与 GlassFish 3.0 一起使用。

我有以下托管 Bean:

@ManagedBean
@RequestScoped
public class OverviewController

    private List<Event> eventList;

    @PostConstruct
    public void init()
        System.out.println("=> OverviewController - init() - enter");

        System.out.println("=< OverviewController - init() - exit");
    

overview.xhtml 文件中,我从我的 OverviewController 调用不同的属性或方法。

<ui:repeat var="event" value="#overviewController.eventList">
    ...
</ui:repeat>

一切正常,但问题出在日志文件上:

INFO: Enter : RESTORE_VIEW 1
INFO: Exit : RESTORE_VIEW 1

INFO: Enter : RENDER_RESPONSE 6
INFO: => OverviewController - init() - enter
INFO: => Overview Controller - updateSelectedTab() - enter
INFO: =< Overview Controller - updateSelectedTab() - exit
INFO: =< OverviewController - init() - exit
INFO: => OverviewController - init() - enter
INFO: => Overview Controller - updateSelectedTab() - enter
INFO: =< Overview Controller - updateSelectedTab() - exit
INFO: =< OverviewController - init() - exit
INFO: Exit : RENDER_RESPONSE 6

如您所见,init() 方法在同一个请求中被调用了两次,没有任何原因。据我所知,任何使用 PostConstruct 注释的方法都会在每个请求中调用一次。我错了吗?

编辑: 页面上没有使用 AJAX。 我用萤火虫检查了请求的数量。有树请求:

1.一个用于javax.faces.resource (GET) 2.一个用于css文件(GET) 3.一个用于overview.xhtml (GET)

【问题讨论】:

您是指 ClassFish 还是 GlassFish? 您是否正在执行任何 Ajax 调用?使用 FireBug 或类似插件来了解浏览器实际发出了多少请求。 @PederN 我更新了问题。 在这个页面上有一些调试 JSF 生命周期的技巧。看看吧,说不定有什么可以帮到你balusc.blogspot.com/2006/09/debug-jsf-lifecycle.html 谢谢!可悲的是,我找不到任何可以解释我的问题的东西。似乎所有用@PostConstruct注解的方法在Invoke Application或RenderResponse中都被调用了两次 【参考方案1】:

如果您有多个框架管理同一个 bean 类,就会发生这种情况。例如。 JSF and CDI,或 JSF and Spring,或 CDI and Spring 等。仔细检查 bean 上的配置和注释。

如果您使用 CDI 并且在整个课程中使用多个 @Named 注释,也会发生这种情况。例如,@Named 直接在类上将其注册为托管 bean,另一个在 @Produces getter 方法上。你需要问问自己这是否真的必要。您也可以只使用#bean.someObject 而不是#someObject

@Named
@RequestScoped
public class Bean 

    @PostConstruct
    public void init() 
        // ...
    

    @Named
    @Produces
    public SomeObject getSomeObject() 
        // ...
    


如果您的托管 bean 扩展了一些抽象类,而该抽象类又在方法上具有 @PostConstruct,也会发生这种情况。您应该从中删除注释。或者,您应该使 init 方法抽象并且 在实现 bean 上具有 @PostConstruct

public abstract class BaseBean 

    @PostConstruct
    public void postConstruct() 
        init();
    

    public abstract void init();


【讨论】:

谢谢!我没有多个框架,但这有助于我理解问题所在。我所有的 ManagedBeans 都扩展了 BaseController。这个 BaseController 有一个 @PostConstruct init() 方法,我认为它会被其他 ManagedBeans 的 PostConstruct init() 覆盖。似乎两个init() 都被调用了。现在一切都说得通了……谢谢! @PostConstruct 不应包含在 BaseController 类中。删除它。 @BalusC:我有一个小问题。关于在同一个bean上使用JSF和CDI,如果我使用@Inject将CDI bean注入@ManagedBean@PostConstruct方法会被调用两次吗?我不太确定如何在同一个 bean 上应用多个框架。我认为框架是通过用@ManagedBean@Named等注释bean来决定的。 @BalusC 我有同样的问题。我在@Controller 类中定义了@PostConstruct 方法。它有什么问题吗?实际上,我想在应用程序部署上启动我的调度程序。有没有其他办法?【参考方案2】:

init() 方法和 @PostConstruct 方法都可能正在触发并导致此行为。尝试更改 init() 方法的名称和/或将其命名为 private。我认为这可能与您的问题有关:

http://javahowto.blogspot.com/2011/07/servlet-init-method-vs-postconstruct.html

我还在这里找到了一篇关于调试 JSF 生命周期的好帖子: Debug JSF lifecycle

【讨论】:

这毫无意义。 JSF 托管 bean 不是 HttpServlet 实现。 我的意思是,根据配置,它可能会导致系统混淆并在两种方法上触发。也许这是一个很长的镜头。感谢您的澄清。 我尝试删除注释,但随后 init() 将被忽略。正如 BalusC 所说,托管 bean 中似乎没有 init() 方法。 @Peder:JSF 对称为init() 的方法绝对没有特殊处理。您对HttpServlet#init() 感到困惑。请重新阅读您自己链接的 javahowto 文章。

以上是关于@PostConstruct 方法为同一个请求调用了两次的主要内容,如果未能解决你的问题,请参考以下文章

@ViewScoped 在每个回发请求上调用 @PostConstruct

即使已经实例化了 ManagedBean(例如在 AJAX 调用上),也会调用 @PostConstruct 方法[重复]

在 @PostConstruct 之后调用 Mockito @Before 方法

如何推迟调用@PostConstruct,直到jUnit设置测试上下文

@PostConstruct方法的使用以及原理,@Component+@PostConstruct方法将一个方法完成初始化操作

一个神奇的标签-@PostConstruct