想要为GlassFish Server添加计时器,不知道从哪里开始 [英] Want to add a timer to GlassFish Server, don't know where to start

查看:114
本文介绍了想要为GlassFish Server添加计时器,不知道从哪里开始的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



至于我目前的项目,我想要使用Glassfish服务器来实现Java EE websocket,并且我已经了解了基础知识。在游戏中实现服务器滴答,每隔几毫秒更新一次服务器,以便连接到服务器的所有会话都能看到同样的东西。



但是,我不不知道从哪里开始与Glassfish合作。我知道我从头开始创建一个服务器并实现一个计时器方法,但是如果可能的话,我宁愿自己保存一些工作。

简单地说,很容易在玻璃鱼服务器中实现计时器/打勾机制(假设它正在运行)?



例如,我想让服务器定期发送单词hello 通过websocket连接到客户端的HTML页面。

>



我们用三个类来解决它:


  1. 调度程序类:时钟它发送一个事件

  2. Websocket端点:基本websocket会话处理程序

  3. Websocket会话处理程序:捕获事件并管理所有websocket会话

带代码的长版

现在对于代码,1)是Mike在评论中提到的一个:一个经典的调度器,它引发了一些事件。这个课程基本上是一个敲响正在倾听其事件的人的时钟。我们有一个EAR = EJB + WAR项目。我们的计时器在EJB模块中,但是如果你有一个WAR,你可以放在那里。

  //一些import 
import javax.enterprise.event.Event;

@Singleton
@Startup
public class TimerBean {

@Inject
private Event< TickEvent> tickEvent;

@Schedule(hour =*,minute =*,second =* / 5)
public void printSchedule(){
tickEvent.fire TickEvent(/ * ...您的初始化... * /));
}

public class TickEvent {
//我们在这里有一些信息,但是您可以
//将其保留为空。
}

}

对于2)websocket端点,这是一个非常学术化的终点。不要忘记,一个连接=一个端点实例。你可以通过 session.getOpenedSessions()从给定的会话中找到所有打开的会话,但我会解释为什么我在下一部分中使用处理程序。

  //一些导入
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
导入javax.websocket.Session;

@ServerEndPoint(value =/ myEndPointPath)
public class TickEndPoint {

@Inject
Private TickSessionHandler sessionHandler;

@OnOpen
public void onOpen(Session session){
sessionHandler.addSession(session);

$ b @OnClose
public void onClose(Session session,CloseReason reason){
sessionHandler.removeSession(session);
}

}

现在,keystone:会话处理程序。会话处理程序是一个ApplicationScoped bean,因此它始终可用。我使用它的原因:


  1. 当TickEvent被触发时,您不知道TickEndPoint实例是否存在,因此事件捕获可能提出一些愚蠢的错误。我们用 @Observes(notifyObserver = Reception.IF_EXISTS)修复了它,但是我们遇到了其他的EJB问题,我将在2中详细介绍。

  2. 出于我还没有确定的原因,当我在@ServerEndPoint中使用@Observes时,我的所有@EJB注入都失败了,因此我将@EJB注入转换为@Inject。但是由于ApplicationScoped是一个CDI bean,@EJB和@Observes在会话处理器类中一起工作得非常好。我们并不真的需要单独的@EJB注释,但为了与其他bean保持一致性,我们希望我们的所有EJB都用@EJB注释。

  3. 监控:您可以监控例如您在时间T发送了多少hello,给您一个时间与连接会话数的关系图。

另外,在我们的特殊情况下,我们有一点可能会在稍后见面。


  1. 我们需要选择SESSIONS的特定子集,而不是全部。在@ServerEndPoint中设置一个静态Set会导致某些东西将其转化为Hulk行为,尤其是当您拥有EJB依赖关系时。在一个游戏的例子中,让我们用蓝队和红队来捕捉国旗情景。如果红队夺得国旗,则需要向蓝队发送哎呀,我们输掉了国旗,并且是的,我们拿到了红队。

  2. 监控:除了连接时间和东西,我们需要诸如上次活动时间和东西等信息。要正确地将它放入JSF数据表中,CDI bean中的列表/集合是最好的选择。

  3. 我在@ApplicationScoped中注解了@ServerEndPoint的一些教程/细节。按照设计(一个服务器端点=一个websocket连接),我感觉不太舒服,所以我拒绝实施这个解决方案。

      @Named 
    @ApplicationScoped
    public class TickSessionHandler {

    //不需要静态Set,最糟糕的是
    //容器不喜欢it
    public Set< Session>会议;

    //让我们初始化这个集合
    public TickSessionHandler {
    this.SESSIONS = new HashSet<>();
    }

    // ----------会话管理
    public void addSession(会话会话){
    this.SESSIONS.add(session );
    }

    public void removeSession(Sesssion session){
    this.SESSIONS.remove(session);
    }

    // ----------收听计时器
    public void onTick(@Observes TickEvent event){

    //如果需要,获取事件属性
    //并继续

    //您的请求:
    this.SESSIONS.forEach(session - > {
    session.getBasicRemote()。sendText(hello);
    });
    }

    }


希望得到这个帮助。解释似乎很长,但核心实现实际上非常轻松。 AFAIK,这样的要求没有捷径。


I'm trying to implement Java EE websockets with a Glassfish server, and I've got the basics down already.

As for my current project, I want to implement server "ticks" like in a game, that update the server every few milliseconds so that all sessions connected to the server see the same thing.

However, I don't know where to start to make this work with Glassfish. I know that I create a server from scratch and implement a timer method, but I'd rather save myself some work here if possible.

Simply put, is it easy to implement a timer/tick mechanism in the glassfish server (assuming it is running)?

For example, I want to make the server periodically send the word "hello" to a client HTML page once they are connected via websocket.

解决方案

Short Version

We solved it with three classes:

  1. Scheduler class: the clock which send an Event
  2. Websocket endpoint: the basic websocket session handler
  3. Websocket session handler: the conductor which catches the Event and manages all the websocket sessions

Long version with code

Now for the code, 1) is the one Mike mentioned in comment: a classic Scheduler which fires some event. This class is basically a clock which knocks whoever is listening to its event. We have a EAR=EJB+WAR project. Our timer is in the EJB module but if you have a single WAR, you can put it there.

// some import
import javax.enterprise.event.Event;

@Singleton
@Startup
public class TimerBean {

    @Inject
    private Event<TickEvent> tickEvent;

    @Schedule(hour = "*", minute = "*", second = "*/5")
    public void printSchedule() {
        tickEvent.fire(new TickEvent(/*...your initialization...*/));
    }

    public class TickEvent{
        // we have some info here but you can 
        // leave it empty.
    }

}

For the 2) websocket endpoint, this is a very academic endpoint. Don't forget that one connection = one endpoint instance. You can find all opened sessions from a given session with session.getOpenedSessions() but I'll explain why I use a handler in the next part.

// some import
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;

@ServerEndPoint(value = "/myEndPointPath")
public class TickEndPoint{

    @Inject
    private TickSessionHandler sessionHandler;

    @OnOpen
    public void onOpen(Session session){
        sessionHandler.addSession(session);
    }

    @OnClose
    public void onClose(Session session, CloseReason reason){
         sessionHandler.removeSession(session);
    }

}

And now the keystone: the session handler. The session handler is an ApplicationScoped bean, so it's always available. The reason I used it:

  1. When TickEvent is fired, you don't know if a TickEndPoint instance exists or not so the event catching may raise some stupid errors. We fixed it with @Observes(notifyObserver = Reception.IF_EXISTS) but we met other EJB problems which I'll detail in 2.
  2. For a reason I haven't identified yet, when I used @Observes in my @ServerEndPoint, all my @EJB injection failed so I switched @EJB injection to @Inject. But as the ApplicationScoped is a CDI bean, @EJB and @Observes work very well together in the session handler class. We didn't really need the @EJB annotation by itself but for design consistency with other bean, we wanted all our EJB to be annotated with @EJB.
  3. Monitoring: you can do monitoring such as how many "hello" you sent at time T, giving you a time vs number of connected sessions graph.

Plus, in our particular situation, we have some point that you may meet later.

  1. We need to select a particular subset of SESSIONS, not all of them. Having a static Set in the @ServerEndPoint led to some-stuff-which-turned-me-into-Hulk behavior especially when you have EJB dependencies. In an example of a game, let's you have capture the flag scenario with blue team and red team. If red team capture the flag, you need to send "Oops, we lost the flag" to the blue team and "Yeah we got it" to the red team.
  2. Monitoring: apart from connection time and stuff, we need info such as "last activity time" and stuff. To properly put it in a JSF datatable, a list/set in a CDI bean is the best option
  3. I encountered some tutorial/detail where the @ServerEndPoint is annotated @ApplicationScoped. By design (one server endpoint = one websocket connection), I don't feel comfortable with it so I refused to implement this solution

    @Named
    @ApplicationScoped
    public class TickSessionHandler{
    
        // There is no need to have a static Set, worst,
        // containers don't like it
        public Set<Session> SESSIONS;
    
        // let's initialize the set
        public TickSessionHandler{
            this.SESSIONS = new HashSet<>();
        }
    
        // ---------- sessions management
        public void addSession(Session session){
            this.SESSIONS.add(session);
        }
    
        public void removeSession(Sesssion session){
            this.SESSIONS.remove(session);
        }
    
        // ---------- Listen to the timer
        public void onTick(@Observes TickEvent event){
    
            // if required, get the event attribute
            // and proceed
    
            // your request:
            this.SESSIONS.forEach(session -> {
                session.getBasicRemote().sendText("hello");
            });
        }
    
    }
    

Hope this help. The explanation seems long but the core implementation is actually very light. AFAIK, there is no shortcut for such requirement.

这篇关于想要为GlassFish Server添加计时器,不知道从哪里开始的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆