Android_OkHttp源码分析

来源:互联网 发布:超级六耳猕猴单法数据 编辑:程序博客网 时间:2024/05/17 08:03

Android_OkHttp源码分析


本文由 Luzhuo 编写,转发请保留该信息.
原文: http://blog.csdn.net/Rozol/article/details/72895794


基本使用

// 网络请求客户端,仅需一个即可OkHttpClient client = new OkHttpClient()// 构建请求Request request = new Request.Builder().url(url).build();// 同步请求Response response = client.newCall(request).execute();// 异步请求client.newCall(request).enqueue(new Callback() {    @Override    public void onFailure(Call call, IOException e) {        e.printStackTrace();    }    @Override    public void onResponse(Call call, Response response) throws IOException {        if (!response.isSuccessful()) {            if(callback != null) callback.onResonse(null);            return;        }        callback.onResonse(response);    }});

源码分析

  • 1: 首先看下Request的构建, Request request = new Request.Builder().url(url).build()
public final class Request {    public Builder() {      this.method = "GET";      this.headers = new Headers.Builder();    }    public Builder url(String url) {      if (url == null) throw new NullPointerException("url == null");      // Silently replace web socket URLs with HTTP URLs.      if (url.regionMatches(true, 0, "ws:", 0, 3)) {        url = "http:" + url.substring(3);      } else if (url.regionMatches(true, 0, "wss:", 0, 4)) {        url = "https:" + url.substring(4);      }      HttpUrl parsed = HttpUrl.parse(url);      if (parsed == null) throw new IllegalArgumentException("unexpected url: " + url);      return url(parsed);    }    Request(Builder builder) {        this.url = builder.url;        this.method = builder.method;        this.headers = builder.headers.build();        this.body = builder.body;        this.tag = builder.tag != null ? builder.tag : this;    }    public Request build() {        if (url == null) throw new IllegalStateException("url == null");        return new Request(this);    }}
- **主要是一些请求信息,如请求头,请求类型,请求数据,解析url等操作,主要看点是通过Build方式构建了Request**
  • 2.1: 先看下OkHttpClient client = new OkHttpClient(),OkHttpClient对象全局仅需要一个就可以了,现在看看里面做了什么?
public OkHttpClient() {        this(new Builder());}public Builder() {      dispatcher = new Dispatcher();      protocols = DEFAULT_PROTOCOLS;      connectionSpecs = DEFAULT_CONNECTION_SPECS;      proxySelector = ProxySelector.getDefault();      cookieJar = CookieJar.NO_COOKIES;      socketFactory = SocketFactory.getDefault();      hostnameVerifier = OkHostnameVerifier.INSTANCE;      certificatePinner = CertificatePinner.DEFAULT;      proxyAuthenticator = Authenticator.NONE;      authenticator = Authenticator.NONE;      connectionPool = new ConnectionPool();      dns = Dns.SYSTEM;      followSslRedirects = true;      followRedirects = true;      retryOnConnectionFailure = true;      connectTimeout = 10_000;      readTimeout = 10_000;      writeTimeout = 10_000;      pingInterval = 0;}
 - 可见Builder()里主要做的还是初始化一些信息
  • 2.2: 然后OkHttpClient调用.newCall(request)

    @Override public Call newCall(Request request) {    return new RealCall(this, request, false /* for web socket */);}RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {    this.client = client;    this.originalRequest = originalRequest;    this.forWebSocket = forWebSocket;    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);}public RetryAndFollowUpInterceptor(OkHttpClient client, boolean forWebSocket) {    this.client = client;    this.forWebSocket = forWebSocket;}
    • 主要是返回了new RealCall()对象,看来精髓都在这里面了
  • 2.3: 现在来看下.execute()做了什么(RealCall.execute())

    final class RealCall implements Call {    // ↓↓↓    synchronized (this) {      if (executed) throw new IllegalStateException("Already Executed");      executed = true;    }    @Override public Response execute() throws IOException {        // ↓↓↓        synchronized (this) {          if (executed) throw new IllegalStateException("Already Executed");          executed = true;        }        captureCallStackTrace();        try {          client.dispatcher().executed(this); // ←←←          Response result = getResponseWithInterceptorChain();          if (result == null) throw new IOException("Canceled");          return result;        } finally {          client.dispatcher().finished(this); // ←←←        }    }    @Override public void enqueue(Callback responseCallback) {        synchronized (this) {          if (executed) throw new IllegalStateException("Already Executed");          executed = true;        }        captureCallStackTrace();        client.dispatcher().enqueue(new AsyncCall(responseCallback)); // ←←←    }}public final class Dispatcher {    private int maxRequests = 64;    private int maxRequestsPerHost = 5;    private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();    private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();    private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();    synchronized void executed(RealCall call) {        runningSyncCalls.add(call); // ←←←    }    synchronized void enqueue(AsyncCall call) {        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {          runningAsyncCalls.add(call); // ←←←          executorService().execute(call); // ←←←        } else {          readyAsyncCalls.add(call);        }    }    public synchronized ExecutorService executorService() {        if (executorService == null) {          executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,              new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));        }        return executorService;    }    void finished(RealCall call) {        finished(runningSyncCalls, call, false);    }    private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {        int runningCallsCount;        Runnable idleCallback;        synchronized (this) {          if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");          if (promoteCalls) promoteCalls();          runningCallsCount = runningCallsCount();          idleCallback = this.idleCallback;        }        if (runningCallsCount == 0 && idleCallback != null) {          idleCallback.run();        }    }}
    • if (executed) throw new IllegalStateException("Already Executed")保证每个call只会被执行一次
    • 可见不管是RealCall.execute()同步执行,还是RealCall.enqueue()异步请求,都会分别往runningSyncCalls和runningAsyncCalls队列里添加. 而RealCall.enqueue()多了一步,就是直接使用线程池执行了
    • 在调用Response result = getResponseWithInterceptorChain()获取到结果后会执行client.dispatcher().finished(this)方法

      void finished(RealCall call) {    finished(runningSyncCalls, call, false);}private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {    int runningCallsCount;    Runnable idleCallback;    synchronized (this) {      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");      if (promoteCalls) promoteCalls(); // ←←←      runningCallsCount = runningCallsCount();      idleCallback = this.idleCallback;    }    if (runningCallsCount == 0 && idleCallback != null) {      idleCallback.run();    }}private void promoteCalls() {    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {      AsyncCall call = i.next();      if (runningCallsForHost(call) < maxRequestsPerHost) {        i.remove();        runningAsyncCalls.add(call);        executorService().execute(call);      }      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.    }}
      • .finished(this)方法很简单,就是从readyAsyncCalls中取出AsyncCall添加到runningAsyncCalls中,然后调用线程池执行
    • 接下来我们看看Response result = getResponseWithInterceptorChain()里做了什么.

      final class RealCall implements Call {    Response getResponseWithInterceptorChain() throws IOException {        // Build a full stack of interceptors.        // ↓↓↓        List<Interceptor> interceptors = new ArrayList<>();        interceptors.addAll(client.interceptors());        interceptors.add(retryAndFollowUpInterceptor);        interceptors.add(new BridgeInterceptor(client.cookieJar()));        interceptors.add(new CacheInterceptor(client.internalCache()));        interceptors.add(new ConnectInterceptor(client));        if (!forWebSocket) {          interceptors.addAll(client.networkInterceptors());        }        interceptors.add(new CallServerInterceptor(forWebSocket));        Interceptor.Chain chain = new RealInterceptorChain(            interceptors, null, null, null, 0, originalRequest);        return chain.proceed(originalRequest); // ←←←    }}public final class RealInterceptorChain implements Interceptor.Chain {    public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,      HttpCodec httpCodec, Connection connection, int index, Request request) {    this.interceptors = interceptors;    this.connection = connection;    this.streamAllocation = streamAllocation;    this.httpCodec = httpCodec;    this.index = index;    this.request = request;    }    @Override public Response proceed(Request request) throws IOException {        return proceed(request, streamAllocation, httpCodec, connection);    }    public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,          Connection connection) throws IOException {        if (index >= interceptors.size()) throw new AssertionError();        calls++;        // If we already have a stream, confirm that the incoming request will use it.        if (this.httpCodec != null && !sameConnection(request.url())) {          throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)              + " must retain the same host and port");        }        // If we already have a stream, confirm that this is the only call to chain.proceed().        if (this.httpCodec != null && calls > 1) {          throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)              + " must call proceed() exactly once");        }        // Call the next interceptor in the chain.        // ↓↓↓        RealInterceptorChain next = new RealInterceptorChain(            interceptors, streamAllocation, httpCodec, connection, index + 1, request);        Interceptor interceptor = interceptors.get(index);        Response response = interceptor.intercept(next);        // Confirm that the next interceptor made its required call to chain.proceed().        if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {          throw new IllegalStateException("network interceptor " + interceptor              + " must call proceed() exactly once");        }        // Confirm that the intercepted response isn't null.        if (response == null) {          throw new NullPointerException("interceptor " + interceptor + " returned null");        }        return response;    }}
      • Response result = getResponseWithInterceptorChain()添加了各种拦截器,比如重试拦截器,缓存拦截,连接拦截 等等.
      • 然后调用chain.proceed(originalRequest), 里面主要通过以下三行代码来实现递归执行执行各种拦截器发起请求,直到得到Response**

        RealInterceptorChain next = new RealInterceptorChain(    interceptors, streamAllocation, httpCodec, connection, index + 1, request);Interceptor interceptor = interceptors.get(index);Response response = interceptor.intercept(next);
  • 3: 拦截器讲解

    public final class RetryAndFollowUpInterceptor implements Interceptor {    private static final int MAX_FOLLOW_UPS = 20;    @Override public Response intercept(Chain chain) throws IOException {        Request request = chain.request();        streamAllocation = new StreamAllocation(client.connectionPool(), createAddress(request.url()), callStackTrace);        int followUpCount = 0;        Response priorResponse = null;        while (true) { // ←←←          if (canceled) {            streamAllocation.release();            throw new IOException("Canceled");          }          Response response = null;          boolean releaseConnection = true;          try {            // ↓↓↓            response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);            releaseConnection = false;          } catch (RouteException e) {            // The attempt to connect via a route failed. The request will not have been sent.            if (!recover(e.getLastConnectException(), false, request)) {              throw e.getLastConnectException();            }            releaseConnection = false;            continue;          } catch (IOException e) {            // An attempt to communicate with a server failed. The request may have been sent.            boolean requestSendStarted = !(e instanceof ConnectionShutdownException);            if (!recover(e, requestSendStarted, request)) throw e;            releaseConnection = false;            continue;          } finally {            // We're throwing an unchecked exception. Release any resources.            if (releaseConnection) {              streamAllocation.streamFailed(null);              streamAllocation.release();            }          }          // Attach the prior response if it exists. Such responses never have a body.          if (priorResponse != null) {            response = response.newBuilder()                .priorResponse(priorResponse.newBuilder()                .body(null)                .build())            .build();          }          // ↓↓↓          Request followUp = followUpRequest(response);          if (followUp == null) {            if (!forWebSocket) {              streamAllocation.release();            }            return response;          }          closeQuietly(response.body());          if (++followUpCount > MAX_FOLLOW_UPS) { // ←←←            streamAllocation.release();            throw new ProtocolException("Too many follow-up requests: " + followUpCount);          }          if (followUp.body() instanceof UnrepeatableRequestBody) { // ←←←            streamAllocation.release();            throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());          }          if (!sameConnection(response, followUp.url())) { // ←←←            streamAllocation.release();            streamAllocation = new StreamAllocation(                client.connectionPool(), createAddress(followUp.url()), callStackTrace);          } else if (streamAllocation.codec() != null) {            throw new IllegalStateException("Closing the body of " + response                + " didn't close its backing stream. Bad interceptor?");          }          request = followUp;          priorResponse = response;        }    }}
  • 首先会调用下个拦截器RetryAndFollowUpInterceptor进行网络重试或重定向,如果非网络线路故障则会调用followUpRequest(response)尝试重定向重连,由于该部分代码被while (true)包裹,所以会不断的尝试,由if (++followUpCount > MAX_FOLLOW_UPS)最多尝试20次.

    public final class BridgeInterceptor implements Interceptor {  @Override public Response intercept(Chain chain) throws IOException {    Request userRequest = chain.request();    Request.Builder requestBuilder = userRequest.newBuilder();    // ...    Response networkResponse = chain.proceed(requestBuilder.build());    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());    Response.Builder responseBuilder = networkResponse.newBuilder()        .request(userRequest);    // ...    return responseBuilder.build();  }}
  • 该拦截器主要是构建一些请求信息,如设置Content-Type,Content-Length,Host等信息,然后调用下个拦截器CacheInterceptor

    public final class CacheInterceptor implements Interceptor {  @Override public Response intercept(Chain chain) throws IOException {    Response cacheCandidate = cache != null        ? cache.get(chain.request())        : null;    long now = System.currentTimeMillis();    // ↓↓↓    CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();    Request networkRequest = strategy.networkRequest;    Response cacheResponse = strategy.cacheResponse;    if (cache != null) {      cache.trackResponse(strategy);    }    if (cacheCandidate != null && cacheResponse == null) {      closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.    }    // If we're forbidden from using the network and the cache is insufficient, fail.    // ↓↓↓    if (networkRequest == null && cacheResponse == null) {      return new Response.Builder()          .request(chain.request())          .protocol(Protocol.HTTP_1_1)          .code(504)          .message("Unsatisfiable Request (only-if-cached)")          .body(Util.EMPTY_RESPONSE)          .sentRequestAtMillis(-1L)          .receivedResponseAtMillis(System.currentTimeMillis())          .build();    }    // If we don't need the network, we're done.    // ↓↓↓    if (networkRequest == null) {      return cacheResponse.newBuilder()          .cacheResponse(stripBody(cacheResponse))          .build();    }    Response networkResponse = null;    try {      // ↓↓↓      networkResponse = chain.proceed(networkRequest);    } finally {      // If we're crashing on I/O or otherwise, don't leak the cache body.      if (networkResponse == null && cacheCandidate != null) {        closeQuietly(cacheCandidate.body());      }    }    // If we have a cache response too, then we're doing a conditional get.    if (cacheResponse != null) {      if (networkResponse.code() == HTTP_NOT_MODIFIED) {        Response response = cacheResponse.newBuilder()            .headers(combine(cacheResponse.headers(), networkResponse.headers()))            .sentRequestAtMillis(networkResponse.sentRequestAtMillis())            .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())            .cacheResponse(stripBody(cacheResponse))            .networkResponse(stripBody(networkResponse))            .build();        networkResponse.body().close();        // Update the cache after combining headers but before stripping the        // Content-Encoding header (as performed by initContentStream()).        cache.trackConditionalCacheHit();        cache.update(cacheResponse, response);        return response;      } else {        closeQuietly(cacheResponse.body());      }    }    Response response = networkResponse.newBuilder()        .cacheResponse(stripBody(cacheResponse))        .networkResponse(stripBody(networkResponse))        .build();    if (HttpHeaders.hasBody(response)) {      CacheRequest cacheRequest = maybeCache(response, networkResponse.request(), cache);      response = cacheWritingResponse(cacheRequest, response);    }    return response;  }}
  • 可见该拦截器会先去获取缓存,if (networkRequest == null && cacheResponse == null)如果缓存和网络都不能用,那么就封装个504的Response返回,if (networkRequest == null)如果网路不能用就封装个缓存的Response返回, 接下来就是网络可以用的时候了,就会调用下个拦截器ConnectInterceptor

    public final class ConnectInterceptor implements Interceptor {  @Override public Response intercept(Chain chain) throws IOException {    RealInterceptorChain realChain = (RealInterceptorChain) chain;    Request request = realChain.request();    StreamAllocation streamAllocation = realChain.streamAllocation();    // We need the network to satisfy this request. Possibly for validating a conditional GET.    boolean doExtensiveHealthChecks = !request.method().equals("GET");    HttpCodec httpCodec = streamAllocation.newStream(client, doExtensiveHealthChecks);    RealConnection connection = streamAllocation.connection();    return realChain.proceed(request, streamAllocation, httpCodec, connection);  }}
  • 该拦截器主要是返回了RealConnection连接对象,然后就执行下个拦截器CallServerInterceptor

    public final class CallServerInterceptor implements Interceptor {  @Override public Response intercept(Chain chain) throws IOException {    // ...    if (responseBuilder == null) {        Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);        request.body().writeTo(bufferedRequestBody); // ←←←        bufferedRequestBody.close();    }    httpCodec.finishRequest();    if (responseBuilder == null) {      responseBuilder = httpCodec.readResponseHeaders(false); // ←←←    }    Response response = responseBuilder        .request(request)        .handshake(streamAllocation.connection().handshake())        .sentRequestAtMillis(sentRequestMillis)        .receivedResponseAtMillis(System.currentTimeMillis())        .build();    int code = response.code();    if (forWebSocket && code == 101) {      // Connection is upgrading, but we need to ensure interceptors see a non-null response body.      response = response.newBuilder()          .body(Util.EMPTY_RESPONSE)          .build();    } else {      response = response.newBuilder()          .body(httpCodec.openResponseBody(response)) // ←←←          .build();    }    // ...  }}public final class MultipartBody extends RequestBody {  @Override public void writeTo(BufferedSink sink) throws IOException {    writeOrCountBytes(sink, false);  }  private long writeOrCountBytes(BufferedSink sink, boolean countBytes) throws IOException {    long byteCount = 0L;    Buffer byteCountBuffer = null;    if (countBytes) {      sink = byteCountBuffer = new Buffer();    }    for (int p = 0, partCount = parts.size(); p < partCount; p++) {      Part part = parts.get(p);      Headers headers = part.headers;      RequestBody body = part.body;      sink.write(DASHDASH);      sink.write(boundary);      sink.write(CRLF);      if (headers != null) {        for (int h = 0, headerCount = headers.size(); h < headerCount; h++) {          sink.writeUtf8(headers.name(h))              .write(COLONSPACE)              .writeUtf8(headers.value(h))              .write(CRLF);        }      }      MediaType contentType = body.contentType();      if (contentType != null) {        sink.writeUtf8("Content-Type: ")            .writeUtf8(contentType.toString())            .write(CRLF);      }      long contentLength = body.contentLength();      if (contentLength != -1) {        sink.writeUtf8("Content-Length: ")            .writeDecimalLong(contentLength)            .write(CRLF);      } else if (countBytes) {        // We can't measure the body's size without the sizes of its components.        byteCountBuffer.clear();        return -1L;      }      sink.write(CRLF);      if (countBytes) {        byteCount += contentLength;      } else {        body.writeTo(sink);      }      sink.write(CRLF);    }    sink.write(DASHDASH);    sink.write(boundary);    sink.write(DASHDASH);    sink.write(CRLF);    if (countBytes) {      byteCount += byteCountBuffer.size();      byteCountBuffer.clear();    }    return byteCount;  }}public final class Http2Codec implements HttpCodec {  @Override public Response.Builder readResponseHeaders(boolean expectContinue) throws IOException {    List<Header> headers = stream.takeResponseHeaders();    Response.Builder responseBuilder = readHttp2HeadersList(headers);    if (expectContinue && Internal.instance.code(responseBuilder) == HTTP_CONTINUE) {      return null;    }    return responseBuilder;  }  public static Response.Builder readHttp2HeadersList(List<Header> headerBlock) throws IOException {    StatusLine statusLine = null;    Headers.Builder headersBuilder = new Headers.Builder();    for (int i = 0, size = headerBlock.size(); i < size; i++) {      Header header = headerBlock.get(i);      // If there were multiple header blocks they will be delimited by nulls. Discard existing      // header blocks if the existing header block is a '100 Continue' intermediate response.      if (header == null) {        if (statusLine != null && statusLine.code == HTTP_CONTINUE) {          statusLine = null;          headersBuilder = new Headers.Builder();        }        continue;      }      ByteString name = header.name;      String value = header.value.utf8();      if (name.equals(RESPONSE_STATUS)) {        statusLine = StatusLine.parse("HTTP/1.1 " + value);      } else if (!HTTP_2_SKIPPED_RESPONSE_HEADERS.contains(name)) {        Internal.instance.addLenient(headersBuilder, name.utf8(), value);      }    }    if (statusLine == null) throw new ProtocolException("Expected ':status' header not present");    return new Response.Builder()        .protocol(Protocol.HTTP_2)        .code(statusLine.code)        .message(statusLine.message)        .headers(headersBuilder.build());  }  @Override public ResponseBody openResponseBody(Response response) throws IOException {    Source source = new StreamFinishingSource(stream.getSource());    return new RealResponseBody(response.headers(), Okio.buffer(source));  }}
    • 可见该拦截器主要是发送和接收网络数据的
  • 执行的流程图:

其他补充

  • 通过Build方式构建对象的实现案例

    package me.luzhuo.okhttpdemo.other.huild;import java.util.ArrayList;import java.util.List;/** * ================================================= * <p> * Author: Luzhuo * <p> * Version: 1.0 * <p> * Creation Date: 2017/6/6 18:39 * <p> * Description: 假设现在有台PC电脑,需要一些软件,我们通过Build的方式添加这些软件 * <p> * Revision History: * <p> * Copyright: Copyright 2017 Luzhuo. All rights reserved. * <p> * ================================================= **/public class PC {    final String system; // 系统,这个必须优先于其他被安装    final List<String> software; // 应用软件    final List<String> hardware; // 硬件(移动硬盘,鼠标之类的)    PC(PC.Builder builder) {        this.system = builder.system;        this.software = builder.software;        this.hardware = builder.hardware;    }    @Override    public String toString() {        return "PC{" +                "system='" + system + '\'' +                ", software=" + software +                ", hardware=" + hardware +                '}';    }    public static class Builder {        String system;        List<String> software;        List<String> hardware;        public Builder() {            this.system = "Windows 10";            software = new ArrayList<>();            hardware = new ArrayList<>();        }        public PC.Builder software(String soft) {            this.software.add(soft);            return this;        }        public PC.Builder hardware(String hardware) {            this.hardware.add(hardware);            return this;        }        public PC build() {            return new PC(this);        }    }}
    • 测试代码

      public class BuildTest {    public static void main(String[] args) {        PC pc = new PC.Builder()                .software("QQ")                .software("Office")                .software("Google Chrome")                .hardware("Mouse")                .hardware("External Hard Disk")                .build();        System.out.println("BuildActivity: " + pc.toString());    }}
      • 打印: BuildActivity: PC{system='Windows 10', software=[QQ, Office, Google Chrome], hardware=[Mouse, External Hard Disk]}
  • 拦截器的实现: 拦截器的实现主要采用了责任链设计模式

    • 假设CEO处理有一个任务,交给了CTO处理, CTO转交给PM处理, PM转交给Programmer处理, Programmer将Task处理成Product之后按原路返回,最后到CEO手里

      • 定义拦截器接口和拦截器锁链式实现

        public interface Interceptor {    Product intercept(Interceptor.Chain chain);    interface Chain {        Task task();        Product proceed(Task task);    }}public class RealInterceptorChain implements Interceptor.Chain {    private final List<Interceptor> interceptors;    private final int index;    private final Task task;    public RealInterceptorChain(List<Interceptor> interceptors, int index, Task task) {        this.interceptors = interceptors;        this.index = index;        this.task = task;    }    @Override    public Task task() {        return this.task;    }    @Override    public Product proceed(Task task) {        if (index >= interceptors.size()) throw new AssertionError();        // Call the next interceptor in the chain.        RealInterceptorChain next = new RealInterceptorChain(interceptors, index + 1, task);        Interceptor interceptor = interceptors.get(index);        Product product = interceptor.intercept(next);        return product;    }}
      • 实现拦截器接口(这里只粘贴了CEOInterceptor和ProgrammerInterceptor拦截器实现代码, CTO和PM拦截器的代码同CEO,这里不再粘贴了)

        public class CEOInterceptor implements Interceptor {    @Override    public Product intercept(Chain chain) {        Task task = chain.task();        System.out.println("CEO阅读了: " + task);        task.autographs("CEO");        Product product = chain.proceed(task);        return product;    }}public class ProgrammerInterceptor implements Interceptor {    @Override    public Product intercept(Chain chain) {        Task task = chain.task();        System.out.println("Programmer正在处理: " + task);        // 程序员做出的牛逼的产品并将其返回        Product product = new Product("牛逼的产品!");        return product;    }}
        • 一个任务代码,另一个是产品代码, Programmer将任务转成了产品返回
        public class Task {    String taskName = "这是一个很重要的任务!!!";    List<String> autographs; // 已阅读该任务的管理们要在这里签字    public Task(){        autographs = new ArrayList<>();    }    public void autographs(String name){        autographs.add(name);    }    @Override    public String toString() {        return "Task{" +                "taskName='" + taskName + '\'' +                ", autographs=" + autographs +                '}';    }}public class Product {    String productName;    public Product(String productName){        this.productName = productName;    }    @Override    public String toString() {        return "Product{" +                "productName='" + productName + '\'' +                '}';    }}
        • 测试代码
        public class InterceptorTest {    public static void main(String[] args) {        RealCall call = new RealCall();        Product product = call.getProductWithInterceptorChain();        System.out.println("InterceptorTest:" + product);    }}class RealCall{    Task task;    RealCall(){        task = new Task();    }    Product getProductWithInterceptorChain(){        List<Interceptor> interceptors = new ArrayList<>();        interceptors.add(new CEOInterceptor());        interceptors.add(new CTOInterceptor());        interceptors.add(new PMInterceptor());        interceptors.add(new ProgrammerInterceptor());        Interceptor.Chain chain = new RealInterceptorChain(interceptors, 0, task);        return chain.proceed(task);    }}
      • 打印:

        CEO阅读了: Task{taskName='这是一个很重要的任务!!!', autographs=[]}CTO阅读了: Task{taskName='这是一个很重要的任务!!!', autographs=[CEO]}PM阅读了: Task{taskName='这是一个很重要的任务!!!', autographs=[CEO, CTO]}Programmer正在处理: Task{taskName='这是一个很重要的任务!!!', autographs=[CEO, CTO, PM]}InterceptorTest:Product{productName='牛逼的产品!'}
原创粉丝点击