一步步学WebSocket(2)编程式WebSocket

上篇,这篇我们采用编程式WebSocket实现上篇的例子:

服务端Endpoint,不再使用ServerEndpoint注解:

public class ProgramerServer extends Endpoint {
    @Override
    public void onOpen(Session session, EndpointConfig edc) {
        System.out.println("Somebody is coming!");
        
        session.addMessageHandler(new MessageHandler.Whole<String>() {

            @Override
            public void onMessage(String message) {
                System.out.println(message); 
                try {
                    session.getBasicRemote().sendText("it is sickening");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

   @Override
   public void onClose(Session session, CloseReason closeReason) {
        // NO-OP by default
    }
   @Override
    public void onError(Session session, Throwable throwable) {
        // NO-OP by default
    }
}

而是继承一个Endpoint抽像类,我们发现Endpoint提供的三个方法:onOpen,onClose,onError。

与在声明式WebSocket中存在的四件套:@OnOpen,@OnClose,@OnMessage , @OnError, 相比少了@OnMessage。

那收到消息之后回调什么呢? 从上面的代码可以看到为session增加的MessageHandler有一个相似方法onMessage。对,就是他。接收到消息为调用的就是这个handler的onMessage方法。

难道两种编程方式的运行逻辑还不相同? 其实不然,对于声明式编程,也是通过MessageHandler回调@OnMessage标记的方法。只是这个过程在声明式编程模式中,被Tomcat等作了包装。

(这里透一点,对于声明式编程, Tomcat都会将其转换成本篇的这种模式, 声明式编程中POJO没有继承Endpoint抽像类,Tomcat自已构造一个Endpoint的子类,在Tomcat8中叫PojoEndpointServer。如下继承关系:

public class PojoEndpointServer extends PojoEndpointBase
public abstract class PojoEndpointBase extends Endpoint.

后端的运行采用PojoEndpointServer委托给我们的POJO类就可以,同样道理

@ClientEndpoint注解的POJO对应到PojoEndpointClient。)

发现没,没有ServerEndpoint注解, 无法配置端点的映射路径? 这里我们需要声明一个ServerApplicationConfig实体(还记和Restful WS中的那个javax.rs.ws.core.Application吗?)来完成这个功能:

public class MyApplicationConfig implements ServerApplicationConfig{

    @Override
    public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> allClasses) {
        return null;
    }

    @Override
    public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> end) {
        ServerEndpointConfig sec =  ServerEndpointConfig.Builder.create(ProgramerServer.class, "/chat")
        .configurator(new ServerEndpointConfig.Configurator(){
        }).build();
        
        
       return new HashSet<ServerEndpointConfig>(){{
           add(sec);
       }};
    }
}

getEndpointConfig构建了一个ServerEndpointConfig集合,上一篇声明式WebSocket为什么不需要这个? 同样需要,只是在声明式WebSocket中Tomcat可以通过@ServerEndpoint注解去构建他。参看Tomcat代码:

 @Override
    public void addEndpoint(Class<?> pojo) throws DeploymentException {

        ServerEndpoint annotation = pojo.getAnnotation(ServerEndpoint.class);
      
        // ServerEndpointConfig
        ServerEndpointConfig sec;
        Class<? extends Configurator> configuratorClazz =
                annotation.configurator();
        Configurator configurator = null;
        if (!configuratorClazz.equals(Configurator.class)) {
            try {
                configurator = annotation.configurator().newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                throw new DeploymentException(sm.getString(
                        "serverContainer.configuratorFail",
                        annotation.configurator().getName(),
                        pojo.getClass().getName()), e);
            }
        }
        sec = ServerEndpointConfig.Builder.create(pojo, path).
                decoders(Arrays.asList(annotation.decoders())).
                encoders(Arrays.asList(annotation.encoders())).
                subprotocols(Arrays.asList(annotation.subprotocols())).
                configurator(configurator).
                build();

        addEndpoint(sec);
    }

Tomcat为每一个ServerEndpoint构造了一个ServerEndpointConfig。

将上面两个类同时,打入War包,部署到Tomcat上,一个WebSocket服务端就OK了。

现在你可以用上篇的Client去访问这个WebSocket。或者你已厌倦了Annocation. 来一个编程式Client吧:

public class ProgramerClient extends Endpoint {

    @Override
    public void onOpen(Session session, EndpointConfig edc) {
        System.out.println("I was accpeted by her!");
        session.addMessageHandler(new MessageHandler.Whole<String>() {

            @Override
            public void onMessage(String message) {
                System.out.println("she say: " + message); 
            }
        });
    }

}

为什么没有onClose,onError方法? 因为Endpoint中有默认实现,这里就没有重载。

public class Client {
    public static void main(String[] args) throws DeploymentException, IOException, InterruptedException {

        WebSocketContainer ws = ContainerProvider.getWebSocketContainer();
        String url = "ws://localhost:8080/ChatWeb2/chat";
        
        ClientEndpointConfig cec = ClientEndpointConfig.Builder.create().configurator(new MyClientConfigurator()).build();
        Session session = ws.connectToServer(ProgramerClient.class,cec,URI.create(url));
        session.getBasicRemote().sendText("Hello,chick!");
        Thread.currentThread().sleep(10000);
    }
}

等等,有点不同。当然了,这里没有了ClientEndpoint,当然也就没有了@ClientEndpoint.Configurator字段(还记得@ClientEndpoint的结构吗?)

当然也就没有了ClientEndpointConfig。所以需要我们自已加一个。

可以看出编程式WebSocket端点比Annotation复杂了很多。采用Annotation提示使用编程变得简单,

而对于WebSocket容器(即本文的Tomcat等)则需要将这种Annotation提示转换成执行代码。

为了大家对两种模式有个整体的认识,中间的细节我们都跳过了。希望不会对大家的理解带来障碍。

时间: 2024-10-02 05:50:07

一步步学WebSocket(2)编程式WebSocket的相关文章

一步步学WebSocket(1)声明式WebSocket

本节描述声明式WebSocket编程,可以与后一篇编程式WebSocket作对比学习: 首先上服务端: @ServerEndpoint("/chat") public class DeclarativeServer {     @OnOpen       public void onOpen(Session session) {           System.out.println("Somebody is coming!");      }          

一文解析Spring编程式和声明式事务实例讲解

接上一篇:一文解析Spring事务管理详解:通俗易懂,轻松掌握! Spring事务管理 Spring支持两种方式的事务管理: 编程式事务管理:?通过Transaction Template手动管理事务,实际应用中很少使用, 使用XML配置声明式事务:?推荐使用(代码侵入性最小),实际是通过AOP实现 实现声明式事务的四种方式: 基于 TransactionInterceptor 的声明式事务:?Spring 声明式事务的基础,通常也不建议使用这种方式,但是与前面一样,了解这种方式对理解 Spri

spring ----编程式事务和声明式事务

一. 事务 事务管理对于企业应用而言是非常重要的,事务的存在保证了用户的每一次操作都是可靠的,当用户操作出现异常时也不至于破坏了后台的数据.例如银行的自动取款机,万一你在转账的时候出现了异常,事务机制会保证你后台的数据还是出异常操作之前的数据,也就是是你出异常的这些操作失效. 事务就是一组由于逻辑上紧密关联而合并成一个整体(工作单元)的多个数据库操作,这些操作要么都执行,要么都不执行. 银行转账操作:开启事务,就是保证转账的操作要么都执行,要么都不执行. 如果在你的账户减去转账金额后出现异常,不

一步步学敏捷开发:开篇

一步步学敏捷开发:开篇 http://www.cnblogs.com/jetlian/p/3913687.html

一步步学敏捷开发:1. Scrum概述

Scrum概述 Scrum概述无非就是敏捷宣言.敏捷原则.Scrum框架和价值观.在之前先看段比较专业的Scrum介绍. Scrum是跨职能团队以迭代.增量的方式开发产品或项目的一种开发框架.它把开发组织成被称为Sprint的工作周期.这些迭代每个都不超过4周(最常见的是两周),并且无间歇地相继进行.Sprint是受时间箱限制的,无论工作完成与否它们都会在特定日期结束,并且从不延长.通常由Scrum团队来选定一个Sprint的时长,并且对于他们所有的Sprint都使用这一时长,直到这个团队能力提

Spring学习8-Spring事务管理(编程式事务管理)

一.Spring事务的相关知识   1.事务是指一系列独立的操作,但在概念上具有原子性. 比如转账:A账号-100, B账号+100,完成.这两个操作独立是没问题的. 但在逻辑上,要么全部完成,要么一起失败.    1)jdbc事务:每个Connection都带有一个事务,只是默认被设置为自动提交.一个连接可以有多个事务.对于JDBC,只有在同一个连接内,才有讨论是否提交的前提. 2)Hibernate事务:本质上也是使用JDBC来处理事务.但是不是直接操作,而是使用Session来操作事务.S

websocket(二) websocket的简单实现,识别用户属性的群聊

没什么好说的,websocket实现非常简单,我们直接看代码. 运行环境:jdk8 tomcat8 无须其他jar包. 具体环境支持自己百度 package com.reach.socketController; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CopyOnWriteArraySet; import javax.annot

全面分析 Spring 的编程式事务管理及声明式事务管理

转自:http://www.open-open.com/lib/view/open1414310646012.html 关于本教程 本教程将深切讲授 Spring 庞杂而丁壮夜的事务治理功用,包括编程式事务和声明式事务.经由进程对本教程的进修,您将可以理解 Spring 事务治理的实质,并无邪运用之. 先决前提 本教程假定您已掌控了 Java 根蒂根抵常识,并对 Spring 有一定意见.您还需求具有根抵的事务治理的常识,好比:事务的界说,隔离级其他概念,等等.本文将直接行使这些概念而不做具体正

Spring笔记(四): spring的编程式事务与声明式事务

一.Spring 事务属性分析 事务管理对于企业应用而言至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作过程中机器突然出故障的情况,此时,事务就必须确保出故障前对账户的操作不生效,就像用户刚才完全没有使用过取款机一样,以保证用户和银行的利益都不受损失. 在 Spring 中,事务是通过 TransactionDefinition 接口来定义的.该接口包含与事务属性有关的方法.在