如何从服务器中运行的线程触发CDI事件?

时间:2017-07-14 08:13:51

标签: java multithreading event-handling cdi tomcat8

我希望我的udp服务器在一个线程中运行,每次收到数据报时都会触发一个事件,发送格式为json的数据。

    public class UDPServer extends Thread {

        private SocketUDPCommunication comm;

        @Inject @Notify
        private StatusChangeHandler sch;

        public UDPServer() {
            comm = new SocketUDPCommunication();
        }


        @Override
        public void run() {

            DatagramPacket response;

            comm.setPort(Utils.UDP_SERVER_PORT);
            comm.createSocket();

            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("Waiting for clients to connect on port:" + comm.getSocket().getLocalPort());
                try {
                    response = comm.receiveResponse();
                } catch (SocketTimeoutException e) {
                    continue;
                }                           

                byte[] byteSend = comm.discardOffset(response);

                Status status = frameToJson(byteSend);

                Genson genson = new Genson();
                String json = genson.serialize(status);

                sch.sendChangedStatus(json);    //Raise the cdi event, sch not initialized!!
            }

        }

        @Override
        public void interrupt() {
            super.interrupt();
            comm.closeConnection();
        }
    }

为此事件定义了一个侦听器,它将调用websocket端点方法将此消息广播到所有连接的客户端:

    public class StatusChangeObserver {

        public void statusChanged(@Observes StatusChange sce) {
            WebsocketEndPoint.sendAll(sce.getJson());
        }
    }

    @ServerEndpoint(value="/websocket")
    public class WebsocketEndPoint {
        private static Set<Session> userSessions = Collections.synchronizedSet(new HashSet<Session>());

        @OnOpen
        public void onOpen(Session userSession) {
            System.out.println("Opening new connection");
            userSessions.add(userSession);
        }

        @OnClose
        public void onClose(Session userSession) {
            System.out.println("Connection closed. Id: " + userSession.getId());
            userSessions.remove(userSession);
        }


        public static void sendAll(String message) {
            for (Session session : userSessions) {
                if (session.isOpen()) {
                    session.getAsyncRemote().sendText(message);
                }
            }     
        }
    }

将实际触发事件的处理程序:

    @Notify
    public class StatusChangeHandler {

        @Inject
        private Event<StatusChange> statusChangedEvent;

        public void sendChangedStatus(String json) {
            StatusChange sce = new StatusChange(json);
            statusChangedEvent.fire(sce);
        }
    }

StatusChange是一个简单的POJO,它将包含要广播的消息。 @Notify限定符:

    @Qualifier
    @Retention(RUNTIME)
    @Target({METHOD, FIELD, PARAMETER, TYPE})
    public @interface Notify {
    }

这是我使用依赖注入的第一步,所以我不太确定如何从线程中触发事件,以及如何初始化sch对象。 我发现this page建议使用WeldWeldContainer类来初始化CDI,但我无法使用maven找到这个类。这是正确的做法吗?在这种情况下,任何人都知道如何将这些类包含在我的项目中?

2 个答案:

答案 0 :(得分:0)

这里有一个带焊接库的公共存储库。

https://mvnrepository.com/artifact/org.jboss.weld

但是,你需要什么?在环境中你会用它吗?例如,在wildfly中,集成了cdi 1.1或cdi 1.2,您无需添加此库。

有关详细信息,请使用http://weld.cdi-spec.org/

答案 1 :(得分:0)

由于您使用的是Tomcat,我们正在讨论 servlet 环境。为此,Weld提供了一个servlet JAR,它将自动为您启动CDI。无需手动处理Weld / WeldContainer

这是一个link to Weld documentation,它解释了您需要哪些工件/依赖项以及如何使用它。

添加之后,CDI应该在您将应用程序部署到Tomcat时为您自行引导。