从@Startup @Singleton Bean的@Schedule方法调用@ViewScoped Bean报NullPointerException
在带有@Startup和@Singleton注解的TimerBean中,通过@Schedule注解的定时方法调用@ViewScoped注解的TestBean的test()方法时,始终抛出NullPointerException错误。
TimerBean 代码
package lv.vda.luis_web.messager.boundary; import javax.ejb.AccessTimeout; import javax.ejb.Schedule; import javax.ejb.Singleton; import javax.ejb.Startup; import javax.inject.Inject; import java.io.Serializable; @Startup @Singleton public class TimerBean implements Serializable { @Inject private TestBean testBean; @Schedule(hour = "*", minute = "*", second = "*/20", info = "") @AccessTimeout(value = 50000) private void timer() { testBean.test(); } }
TestBean 代码
package lv.vda.luis_web.messager.boundary; import javax.faces.view.ViewScoped; import javax.inject.Named; import java.io.Serializable; @Named @ViewScoped public class TestBean implements Serializable { public void test() { System.out.println("Checking is ok"); } }
错误日志
14:46:40,008 ERROR [org.jboss.as.ejb3.timer] (EJB default - 3) WFLYEJB0020: Error invoking timeout for timer: [id=90f8d796-c627-4e49-99a1-51af55c10c94 timedObjectId=luis_web.luis_web.TimerBean auto-timer?:true persistent?:true timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@6e86bb33 previousRun=Thu Sep 12 14:36:00 EEST 2024 initialExpiration=null intervalDuration(in milli sec)=0 nextExpiration=Thu Sep 12 14:47:00 EEST 2024 timerState=IN_TIMEOUT info=] ScheduleExpression [second=/20;minute=;hour=;dayOfMonth=;month=;dayOfWeek=;year=*;timezoneID=null;start=null;end=null]: javax.ejb.EJBException: java.lang.NullPointerException
- 视图作用域的生命周期限制:
@ViewScoped是JSF专属作用域,它的生命周期完全绑定到单个JSF视图(即浏览器中的一个页面实例)。只有当用户打开对应的JSF页面、视图被创建时,该Bean才会被实例化;视图销毁(如页面关闭、跳转)时,Bean也会随之销毁。而TimerBean是@Startup+@Singleton,应用启动时就初始化完成,定时任务在后台独立运行,此时不存在任何JSF视图,容器无法创建或注入@ViewScoped的TestBean,导致testBean为null。 - 作用域依赖不兼容:Singleton是应用级作用域,生命周期从应用启动持续到关闭;ViewScoped是视图级作用域,生命周期远短于Singleton。将短作用域Bean注入到长作用域Bean中,违背CDI的作用域规则——当Singleton需要使用ViewScoped Bean时,该Bean可能根本不存在,容器无法提供有效实例。
内容的提问来源于stack exchange,提问作者Pegus

