简体   繁体   English

Clojure:实现有状态的Java接口

[英]Clojure: implementing stateful Java interface

Kafka Streams has an interface, Processor , the implementation of which is stateful. Kafka Streams有一个接口, Processor ,其实现是有状态的。 An example implementation given in the developer guide is: 开发人员指南中给出的示例实现是:

public class WordCountProcessor implements Processor<String, String> {

  private ProcessorContext context;
  private KeyValueStore<String, Long> kvStore;

  @Override
  @SuppressWarnings("unchecked")
  public void init(ProcessorContext context) {
      // keep the processor context locally because we need it in punctuate() and commit()
      this.context = context;

      // call this processor's punctuate() method every 1000 time units.
      this.context.schedule(1000);

      // retrieve the key-value store named "Counts"
      kvStore = (KeyValueStore) context.getStateStore("Counts");
  }

  @Override
  public void process(String dummy, String line) {
      String[] words = line.toLowerCase().split(" ");

      for (String word : words) {
          Long oldValue = kvStore.get(word);
          if (oldValue == null) {
              kvStore.put(word, 1L);
          } else {
              kvStore.put(word, oldValue + 1L);
          }
      }
  }

  @Override
  public void punctuate(long timestamp) {
      KeyValueIterator<String, Long> iter = this.kvStore.all();
      while (iter.hasNext()) {
          KeyValue<String, Long> entry = iter.next();
          context.forward(entry.key, entry.value.toString());
      }
      iter.close();
      // commit the current processing progress
      context.commit();
  }

  @Override
  public void close() {
      // close the key-value store
      kvStore.close();
  }

}

The init method initializes WordCountProcessor 's internal state, such as retrieving a key-value store. init方法初始化WordCountProcessor的内部状态,例如检索键值存储。 Other methods, like process and close , make use of this state. 其他方法(如processclose )使用此状态。

It's not clear to me how to reify such an interface in Clojure. 这不是我清楚如何reify Clojure中这样的接口。 How would we pass on the state retrieved by init to process , close , etc.? 我们如何将init检索到的状态传递给processclose等?

Using a closure? 使用封闭?

One idea I have is to use a closure: 我有一个想法是使用一个闭包:

(let [ctx (atom nil)]
  (reify Processor
    (close [this]
      ;; Do something w/ ctx
      )
    (init [this context]
      (reset! ctx context))
    (process [this k v]
      ;; Do something w/ ctx
      )
    (punctuate [this timestamp]
      ;; Do something w/ ctx
      )))

Annoyingly, we'd have to start with the ProcessorContext object each time, so the key-value store code would be repeated across all methods that need the key-value store. 令人讨厌的是,我们每次都必须从ProcessorContext对象开始,因此键值存储代码将在需要键值存储的所有方法中重复。

I don't see a (general) way around that, though on a case-by-case basis we can replace the ctx atom with more specific state that the methods need. 我没有看到(通用)方法,虽然根据具体情况,我们可以用方法所需的更具体的状态替换ctx原子。

Is there a better way? 有没有更好的办法?

Closing over an atom would be the main way to do it. 关闭原子将是实现它的主要方式。 Your original class has two fields, so you can close over two atoms to get the same effect 您的原始类有两个字段,因此您可以关闭两个原子以获得相同的效果

(let [ctx (atom nil)
      kv-store (atom nil)]
  (reify Processor
    ,,,
    (init [this context]
      (reset! ctx context)
      (reset! kv-store (.getStateStore context "Counts")))
    ,,,))

If that's still too tedious then you can add some convenience functions that also close over the atoms 如果这仍然太乏味,那么你可以添加一些便利函数,这些函数也会关闭原子

(let [ctx (atom nil)
      kv-store (atom nil)]

  (def kv-get [key]
    (.get @kv-store key))

  (def kv-all []
    (iterator-seq (.all @kv-store)))

  (def kv-put [key value]
    (.put @kv-store key value))

  (reify Processor
    ,,,
    (init [this context]
      (reset! ctx context)
      (reset! kv-store (.getStateStore context "Counts")))
    ,,,
  (punctuate [this timestamp]
    (do-seq [x (kv-all)]
      ,,,)
  )))

The alternative would be to use gen-class , but think you'll be better off with reify. 替代方案是使用gen-class ,但认为你会更好地使用reify。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM