@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方法将一个方法完成初始化操作