观察者模式: 定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,依赖他的对象收到通知并自动更新。
类图解析: 在类图中Subject为被观察者,Observer为观察者。被观察者的attach方法用来添加观察者,notify方法通知观察者;观察者的update方法当被观察者notify是调用。
源码逻辑: 在Kafka client consumer端request相关的部分源码中,也体现了观察者模式。大致逻辑是这样的,consumer想要消费kafka broker中的数据需要发送request,request发送的结果用RequestFuture来表示,RequestFuture中包含RequestFutureListener,当request处理完成后RequestFutureListener的相关方法会被调用。RequestFutureCompletionHandler用来处理RequestFuture、ClientResponse还有RuntimeException。
依赖关系: 在这组依赖关系中,RequestFutureListener为观察者,onSuccess和onFail方法相当于之前的update方法;RequestFuture为被观察者,addListener相当于attach方法,fireSuccess和fireFailure方法相当于notify方法。
RequestFutureListener部分代码:
public interface RequestFutureListener<T> {
void onSuccess(T value);
void onFailure(RuntimeException e);
}
RequestFuture部分代码:
public class RequestFuture<T> implements ConsumerNetworkClient.PollCondition {
private static final Object INCOMPLETE_SENTINEL = new Object();
private final AtomicReference<Object> result = new AtomicReference<>(INCOMPLETE_SENTINEL);
private final ConcurrentLinkedQueue<RequestFutureListener<T>> listeners = new ConcurrentLinkedQueue<>();
private final CountDownLatch completedLatch = new CountDownLatch(1);
public void complete(T value) {
try {
if (value instanceof RuntimeException)
throw new IllegalArgumentException("The argument to complete can not be an instance of RuntimeException");
if (!result.compareAndSet(INCOMPLETE_SENTINEL, value))
throw new IllegalStateException("Invalid attempt to complete a request future which is already complete");
fireSuccess();
} finally {
completedLatch.countDown();
}
}
//遍历listener并调用其success时的方法
private void fireSuccess() {
T value = value();
while (true) {
RequestFutureListener<T> listener = listeners.poll();
if (listener == null)
break;
listener.onSuccess(value);
}
}
//遍历listener并调用其fail时的方法
private void fireFailure() {
RuntimeException exception = exception();
while (true) {
RequestFutureListener<T> listener = listeners.poll();
if (listener == null)
break;
listener.onFailure(exception);
}
}
//增加listener
public void addListener(RequestFutureListener<T> listener) {
this.listeners.add(listener);
if (failed())
fireFailure();
else if (succeeded())
fireSuccess();
}