hazelcast 使用_使用Hazelcast发布和订阅

hazelcast 使用

几周前,我写了一篇有关Hazelcast入门的博客,描述了创建分布式地图,列表和队列是多么简单。 当时我提到,Hazelcast还做很多其他事情。 该博客快速介绍了Hazelcast的另一个功能:基于Publish / Subscribe模式的广播消息系统。 这采用通常的格式,即邮件发件人应用通过该格式发布有关特定主题的邮件。 消息不针对任何特定的客户端,但是可以由对主题感兴趣的任何客户端读取。

发布和订阅的明显场景来自高金融和做市商的世界。 做市商买卖股票之类的金融工具,并通过在通常是电子市场中的买卖价格广告来竞争业务。 为了使用Hazelcast实现非常简单的做市商方案,我们需要三个类: StockPrice bean, MarketMakerClient

以下代码已添加到我在Github上可用的现有Hazelcast项目中。 无需担心其他POM依赖项。

public class StockPrice implements Serializable { 

  private static final long serialVersionUID = 1L; 

  private final BigDecimal bid; 

  private final BigDecimal ask; 

  private final String code; 

  private final String description; 

  private final long timestamp; 

  /** 
   * Create a StockPrice for the given stock at a given moment 
   */ 
  public StockPrice(BigDecimal bid, BigDecimal ask, String code, String description, 
      long timestamp) { 
    super(); 
    this.bid = bid; 
    this.ask = ask; 
    this.code = code; 
    this.description = description; 
    this.timestamp = timestamp; 
  } 

  public BigDecimal getBid() { 
    return bid; 
  } 

  public BigDecimal getAsk() { 
    return ask; 
  } 

  public String getCode() { 
    return code; 
  } 

  public String getDescription() { 
    return description; 
  } 

  public long getTimestamp() { 
    return timestamp; 
  } 

  @Override 
  public String toString() { 

    StringBuilder sb = new StringBuilder("Stock - "); 
    sb.append(code); 
    sb.append(" - "); 
    sb.append(description); 
    sb.append(" - "); 
    sb.append(description); 
    sb.append(" - Bid: "); 
    sb.append(bid); 
    sb.append(" - Ask: "); 
    sb.append(ask); 
    sb.append(" - "); 
    SimpleDateFormat df = new SimpleDateFormat("HH:MM:SS"); 
    sb.append(df.format(new Date(timestamp))); 
    return sb.toString(); 
  } 
}

StockPrice bean具有所有常用的获取器和设置器,可以在任何给定时间模拟股票的买价和买价(以正常语言进行买卖),并且MarketMaker类使用Hazelcast发布这些bean。

通常,做市商会在一种以上的金融工具中发布价格; 但是,为简单起见, MarketMaker在此演示中仅发布单个价格。

public class MarketMaker implements Runnable { 

  private static Random random = new Random(); 

  private final String stockCode; 

  private final String description; 

  private final ITopic<StockPrice> topic; 

  private volatile boolean running; 

  public MarketMaker(String topicName, String stockCode, String description) { 
    this.stockCode = stockCode; 
    this.description = description; 
    this.topic = createTopic(topicName); 
    running = true; 
  } 

  @VisibleForTesting 
  ITopic<StockPrice> createTopic(String topicName) { 
    HazelcastInstance hzInstance = Hazelcast.newHazelcastInstance(); 
    return hzInstance.getTopic(topicName); 
  } 

  public void publishPrices() { 

    Thread thread = new Thread(this); 
    thread.start(); 
  } 

  @Override 
  public void run() { 

    do { 
      publish(); 
      sleep(); 
    } while (running); 
  } 

  private void publish() { 

    StockPrice price = createStockPrice(); 
    System.out.println(price.toString()); 
    topic.publish(price); 
  } 

  @VisibleForTesting 
  StockPrice createStockPrice() { 

    double price = createPrice(); 
    DecimalFormat df = new DecimalFormat("#.##"); 

    BigDecimal bid = new BigDecimal(df.format(price - variance(price))); 
    BigDecimal ask = new BigDecimal(df.format(price + variance(price))); 

    StockPrice stockPrice = new StockPrice(bid, ask, stockCode, description, 
        System.currentTimeMillis()); 
    return stockPrice; 
  } 

  private double createPrice() { 

    int val = random.nextInt(2010 - 1520) + 1520; 
    double retVal = (double) val / 100; 
    return retVal; 
  } 

  private double variance(double price) { 
    return (price * 0.01); 
  } 

  private void sleep() { 
    try { 
      TimeUnit.SECONDS.sleep(2); 
    } catch (InterruptedException e) { 
      e.printStackTrace(); 
    } 
  } 

  public void stop() { 
    running = false; 
  } 

  public static void main(String[] args) throws InterruptedException { 

    MarketMaker bt = new MarketMaker("STOCKS", "BT.L", "British Telecom"); 
    MarketMaker cbry = new MarketMaker("STOCKS", "CBRY.L", "Cadburys"); 
    MarketMaker bp = new MarketMaker("STOCKS", "BP.L", "British Petrolium"); 

    bt.publishPrices(); 
    cbry.publishPrices(); 
    bp.publishPrices(); 

  } 

}

像往常一样,设置Hazelcast相当简单,上面MarketMaker类中的大多数代码与Hazelcast无关。 该课程分为两部分:建筑价格和出版价格。 构造函数接受三个参数,将其存储起来以备后用。 它还创建一个Hazelcast实例,并通过私有createTopic()方法注册一个名为"STOCKS"的简单主题。 如您所料,创建Hazelcast实例并注册主题需要两行代码,如下所示:

ITopic<StockPrice> createTopic(String topicName) { 
    HazelcastInstance hzInstance = Hazelcast.newHazelcastInstance(); 
    return hzInstance.getTopic(topicName); 
  }

该类的其余部分使用线程来调用MarketMakerrun()方法来运行价格发布机制。 此方法生成随机出价,为关联的股票代码要价,并使用Hazelcast发布。 使用以下单行代码即可完成发布:

topic.publish(price);

MarketMaker类的最后一部分是main()方法,其作用是创建多个MarketMaker实例并使它们运行。

既然Hazelcast知道了我们不断变化的股票价格,接下来要做的就是整理客户代码。

public class Client implements MessageListener<StockPrice> { 

  public Client(String topicName) { 
    HazelcastInstance hzInstance = Hazelcast.newHazelcastInstance(); 
    ITopic<StockPrice> topic = hzInstance.getTopic(topicName); 
    topic.addMessageListener(this); 
  } 

  /** 
   * @see com.hazelcast.core.MessageListener#onMessage(com.hazelcast.core.Message) 
   */ 
  @Override 
  public void onMessage(Message<StockPrice> arg0) { 
    System.out.println("Received: " + arg0.getMessageObject().toString()); 
  } 

  public static void main(String[] args) { 

    new Client("STOCKS"); 
  } 

}

与任何消息传递系统一样,消息发送者代码必须知道呼叫谁和呼叫什么。 客户端通过创建Hazelcast实例并在"STOCKS"主题中注册兴趣来实现“调用什么"STOCKS" ,方法与发布者相同,如下所示:

HazelcastInstance hzInstance = Hazelcast.newHazelcastInstance(); 
    ITopic<StockPrice> topic = hzInstance.getTopic(topicName); 
    topic.addMessageListener(this);

通过客户端实现Hazelcast的MessageListener接口及其单一方法onMessage()来实现“呼叫”

@Override 
  public void onMessage(Message<StockPrice> arg0) { 
    System.out.println("Received: " + arg0.getMessageObject().toString()); 
  }

客户端代码的最后一部分是其main()方法,该方法创建一个客户端实例。

最后要做的是运行代码。 为此,我仅将所有必需的JAR文件放在一个目录中,只需考虑两个:hazel cast-3.1.jar和guava-13.0.1.jar。

屏幕截图2013年12月7日的10.51.43

完成后,我转到项目的classes目录:

cd /Users/Roger/git/captaindebug/hazelcast/target/classes

…并解雇了发布者

java -cp ./:/Users/Roger/tmp/mm/guava-13.0.1.jar:/Users/Roger/tmp/mm/hazelcast-3.1.jar com.captaindebug.hazelcast.pubsub.MarketMaker

……然后是客户。

java -cp ./:/Users/Roger/tmp/mm/guava-13.0.1.jar:/Users/Roger/tmp/mm/hazelcast-3.1.jar com.captaindebug.hazelcast.pubsub.Client

当然,如果您正在使用此粗略且准备就绪的技术在计算机上运行此程序,则请记住将其替换
/Users/Roger/tmp/mm ,以及放置这些JAR文件副本的路径。

如果您在一个终端中运行MarketMaker发布者,并在其他两个终端中运行几个客户,那么您将得到类似的信息,在这里您可以看到正在发布的价格以及客户正在接收更新。

屏幕截图2013年12月22日的17.40.07

关于Hazelcast的一件事要注意的是,“ 集群 ”是指Hazelcast实例的集群,而不是JVM的集群。 除非您为每个应用程序请求多个Hazelcast实例,否则这是不明显的。 当其他客户端加入群集时,您将看到类似以下内容:

Members [5] {
Member [192.168.0.7]:5701
Member [192.168.0.7]:5702
Member [192.168.0.7]:5703
Member [192.168.0.7]:5704 this
Member [192.168.0.7]:5705
}

在上面的日志中,有两个侦听器条目,每个侦听器条目一个,每个发布者条目三个,在MarketMakermain()方法中启动的每个MarketMaker实例一个。

屏幕快照2013-12-07 at 11.16.21
这里要考虑的事情是,是否是每个对象实例创建一个Hazelcast实例的好习惯(就像我在示例代码中所做的那样),还是在代码中拥有一个static Hazelcast实例更好。 我不确定该答案是什么,所以如果有任何Hazelcast专家正在阅读此书,请告诉我。

就是这样:Hazelcast可以在发布和订阅模式下愉快地运行,但是我还没有介绍Hazelcast的所有功能。 也许以后再说……

参考: Captain Debug的Blog博客上的JCG合作伙伴 Roger Hughes的Hazelcast发布和订阅

翻译自: https://www.javacodegeeks.com/2014/01/publish-and-subscribe-with-hazelcast.html

hazelcast 使用

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hazelcast 是一个开源的分布式内存数据网格(In-Memory Data Grid),它可以让开发人员更加容易地构建高可用性、高性能的分布式系统。下面是一个使用 Hazelcast 的简单例子: 假设我们正在开发一个在线商城,需要缓存一些商品信息。我们可以使用 Hazelcast 轻松地将这些商品信息存储在分布式内存中。具体步骤如下: 1. 引入 Hazelcast 的依赖 ```xml <dependency> <groupId>com.hazelcast</groupId> <artifactId>hazelcast-all</artifactId> <version>4.0.3</version> </dependency> ``` 2. 编写代码 ```java import com.hazelcast.core.Hazelcast; import com.hazelcast.core.HazelcastInstance; import java.util.Map; public class HazelcastExample { public static void main(String[] args) { // 创建 Hazelcast 实例 HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance(); // 获取分布式 Map Map<String, String> products = hazelcastInstance.getMap("products"); // 将商品信息放入 Map 中 products.put("product1", "iphone"); products.put("product2", "ipad"); products.put("product3", "macbook"); // 获取商品信息 String product1 = products.get("product1"); String product2 = products.get("product2"); String product3 = products.get("product3"); System.out.println(product1); System.out.println(product2); System.out.println(product3); // 关闭 Hazelcast 实例 hazelcastInstance.shutdown(); } } ``` 在上面的例子中,我们首先创建了一个 Hazelcast 实例,然后获取了一个分布式 Map,将商品信息放入 Map 中。最后,我们通过键获取了对应的商品信息,并将其打印出来。最后,我们关闭了 Hazelcast 实例。 需要注意的是,在实际使用中,我们可能需要对 Hazelcast 进行配置,以满足我们的具体需求。此外,我们还可以使用 Hazelcast 的其他功能,例如分布式队列、分布式锁等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值