@Schedule 无法从 @SessionScoped CDI bean 获取数据

Posted

技术标签:

【中文标题】@Schedule 无法从 @SessionScoped CDI bean 获取数据【英文标题】:@Schedule could not fetch data from @SessionScoped CDI bean 【发布时间】:2020-03-16 16:37:42 【问题描述】:

登录后存储在 SessionScoped bean 中的用户数据。 我希望每 5 秒获取存储在会话中的每个帐户并发送到后端。 我的计时器

@Singleton
@Startup
public class FrontendTimer 

    @Inject
    private UserContext userContext;

    @Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
    @Asynchronous
    public void atSchedule() throws InterruptedException 
        System.out.println("Get Logged user stored in the session each 5 seconds ");
        System.out.println("FR " + userContext.getAccount().toString());
    


启动调度程序的唯一方法是创建@Startup 和@Singleton 类。 将用户数据保存在前端的唯一方法,将帐户保存到 SessionScoped CDI bean,不推荐使用 JSF 原生 bean。

你会得到如下错误: WELD-001303:范围类型 javax.enterprise.context.SessionScoped 没有活动上下文

项目地址在这里https://github.com/armdev/eap 自己上课https://github.com/armdev/eap/blob/master/eap-web/src/main/java/io/project/app/beans/FrontendTimer.java

基本上我想要一个可以从 Session Scope 获取数据的标准计时器。

【问题讨论】:

抱歉,您的问题完全不清楚。小心澄清。最好用minimal reproducible example 假设 UserContext 是 sessionscoped,如果没有活动用户并且调用了 atSchedule(),它应该选择哪个 UserContext?或者如果有两个用户处于活动状态,因此存在两个 UserContext - 如果两者都应该选择?会话范围仅在处理 servlet 请求的线程中可用。计划的后台作业中没有用户会话上下文。 @Selaron:哇...阅读帖子(不是代码链接)这个问题对我来说完全没有意义。你的评论(问题)说得很清楚。赞美你确实得到了它。 @kukeltje 谢谢。我想我只是快速阅读关键字、代码和错误消息,而不是试图逐字理解所有内容。有时会有所帮助,有时会严重失败._. 【参考方案1】:

您当前的方法将无法按预期工作,因为每个调度程序调用都将在与会话完全隔离的上下文中发生(因此出现No active contexts... 错误消息)。

我建议你在这里使用一个简单的反转。在你的应用范围单例中,添加一个简单的List<String> currentSessions 和对应的方法到void add(String account)void remove(String account)。然后@Inject 单例进入会话范围的bean(而不是相反)。最后,添加@WebListener 来处理会话事件。

@Singleton
public class SessionManager 

    private List<String> currentSessions;

    @Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
    @Asynchronous
    public void atSchedule() throws InterruptedException 
        //Do something with currentSessions
    

    public void add(String account)
        currentSessions.add(account);
    

    public void remove(String account)
        currentSessions.remove(account);
    


@SessionScoped
public class UserContext implements Serializable 

    @Inject
    private SessionManager sessionManager;

    /*
    ...
    */

    public void sessionCreated()
        sessionManager.add(account.toString());
    

    public void sessionDestroyed()
        sessionManager.remove(account.toString());
    


@WebListener
    public class SessionListener implements HttpSessionListener 

        @Override
        public void sessionCreated(HttpSessionEvent se) 
            HttpSession session = se.getSession();

            FacesContext context = FacesContext.getCurrentInstance();
            UserContext userContext = (UserContext) session.getAttribute("userContext");
            userContext.sessionCreated();
        

        @Override
        public void sessionDestroyed(HttpSessionEvent se) 
            HttpSession session = se.getSession();

            FacesContext context = FacesContext.getCurrentInstance();
            UserContext userContext = (UserContext) session.getAttribute("userContext");
            userContext.sessionDestroyed();

         
    

【讨论】:

是的,完全同意。我使用同样的技术确实能够通过 websockets 向所有登录用户发送消息。 谢谢,我认为这是一个真正的解决方案。

以上是关于@Schedule 无法从 @SessionScoped CDI bean 获取数据的主要内容,如果未能解决你的问题,请参考以下文章

表存在时无法复制到不存在的表中

RXJS:从 of() 移动到 schedule()

请帮忙翻译一下:Effort and schedule slippage for integration & testing

我只需要从 crdd 和 schedule date 中选择 2018 年的记录

oracle里的job和schedule有啥区别

java/安卓关于Timer,task,schedule重新设置定时任务时间的问题