Forest源码探析

Forest 是一个开源的 Java HTTP 客户端框架,它能够将 HTTP 的所有请求信息(包括 URL、Header 以及 Body 等信息)绑定到您自定义的 Interface 方法上,能够通过调用本地接口方法的方式发送 HTTP 请求。

本篇通过分析其源代码,列出了相关重要组件类,并最终通过一个流程图,分析其整个编码实现,以分享给大家。最主要这个工程源代码,通过引入大量设计模式(模板方法、工厂、代理、策略等),使得代码组织地相当美感,整洁,有助于提高你的阅读兴趣,因此写了这篇文章留念并分享给大家。

一、相关介绍

1、为什么使用 Forest?

使用 Forest 就像使用类似 Dubbo 那样的 RPC 框架一样,只需要定义接口,调用接口即可,不必关心具体发送 HTTP 请求的细节。同时将 HTTP 请求信息与业务代码解耦,方便您统一管理大量 HTTP 的 URL、Header 等信息。而请求的调用方完全不必在意 HTTP 的具体内容,即使该 HTTP 请求信息发生变更,大多数情况也不需要修改调用发送请求的代码。

2、Forest 如何使用?

Forest 不需要您编写具体的 HTTP 调用过程,只需要您定义一个接口,然后通过 Forest 注解将 HTTP 请求的信息添加到接口的方法上即可。请求发送方通过调用您定义的接口便能自动发送请求和接受请求的响应。

3、Forest 的工作原理

Forest 会将您定义好的接口通过动态代理的方式生成一个具体的实现类,然后组织、验证 HTTP 请求信息,绑定动态数据,转换数据形式,SSL 验证签名,调用后端 HTTP API(httpclient 等 API)执行实际请求,等待响应,失败重试,转换响应数据到 Java 类型等脏活累活都由这动态代理的实现类给包了。 请求发送方调用这个接口时,实际上就是在调用这个干脏活累活的实现类。

4、Forest 的架构

在这里插入图片描述

5、官网地址

【官网地址】:http://forest.dtflyx.com/

【工程源码】:https://gitee.com/dromara/forest

二、源码分析

由于forest的源代码看起来挺多,但是工程模块划分的相关美感。从包的命名就可以看出来,每个类的职责。下面,主要列举一些重要的类,进而分析其作用。而这些类,构成了整个创建请求、请求组装、请求响应、响应解析等一些列功能。

1、ForestConnectionManager

该类负责通过ForestConfiguration获取相关配置参数,进而创建HttpClient,它包含了两个实现类HttpclientConnectionManagerOkHttp3ConnnectionManager

public interface ForestConnectionManager {

    void init(ForestConfiguration configuration);
}

ForestConnectionManager.png

1.1、OkHttp3ConnectionManager

基于okhttp3实现http connection管理器

public void init(ForestConfiguration configuration) {
        pool = new ConnectionPool();
    }

该类实现了init方法,通过源码可以看出仅仅初始化了ConnectionPool对象。

getClient

其中比较重要的方法

public OkHttpClient getClient(ForestRequest request, LifeCycleHandler lifeCycleHandler)

根据ForestRequestLifeCycleHandler,通过OkHttpClient.Builder建造者创建OkHttpClient实例对象,方法内部初始化了实例的相关参数,包括设置HttpProxy,以及处理是否支持HTTPS协议。

1.2、HttpclientConnectionManager

基于apache httpclient 实现http connection管理器

该类实现了init方法,通过源码可以看出,通过ForestConfiguration类传入的参数,初始化成员变量,成员变量包括如下

private static PoolingHttpClientConnectionManager tsConnectionManager;

private static PoolingNHttpClientConnectionManager asyncConnectionManager;

private static Lookup<AuthSchemeProvider> authSchemeRegistry;

比较重要的成员方法是

public HttpClient getHttpClient(ForestRequest request, CookieStore cookieStore)

,其中也提供了创建异步的CloseableHttpAsyncClient成员方法。

2、HttpExecutor

通过LifeCycleHandler以及ConnectionManager发起Http请求,请求类型包括POSTPOSTPUTDELETE等,接口包含两个重要的方法execute(LifeCycleHandler)close,对于支持apache clientokhttp3,分别提供了对应的抽象类AbstractHttpclientExecutorAbstractOkHttp3Executor

HttpExecutor.png

2.1、AbstractHttpclientExecutor

基于Apache HttpClient实现Http调用的执行器,该类继承了AbstractHttpExecutor类,最核心的方法execute

该类包含三个重要的成员变量

protected final HttpclientResponseHandler httpclientResponseHandler;
protected String url;
protected final String typeName;
protected T httpRequest;
protected BodyBuilder<T> bodyBuilder;
protected CookieStore cookieStore;

以及父类AbstractHttpExecutor类的成员变量

protected final ForestRequest request;
protected HttpclientRequestSender requestSender;
protected ForestResponse response;

该类核心方法

public void execute(int retryCount, LifeCycleHandler lifeCycleHandler)

源码分析

public void execute(int retryCount, LifeCycleHandler lifeCycleHandler) {
    Date startDate = new Date();
    ForestResponseFactory forestResponseFactory = new HttpclientForestResponseFactory();
    try {
        //这里实际委托给 HttpclientRequestSender#sendRequest 发送http请求
        //本身内部通过判断 retryCount 然后进行充实操作,如果重试次数>=request.getRetryCount(),
      	//则调用httpRequest.abort()丢弃本次请求
        requestSender.sendRequest(
                request,
                httpclientResponseHandler,
                httpRequest,
                lifeCycleHandler,
                cookieStore,
                startDate, 0);
    } catch (IOException e) {
        if (retryCount >= request.getRetryCount()) {
            httpRequest.abort();
            response = forestResponseFactory.createResponse(request, null, lifeCycleHandler, e, startDate);
            lifeCycleHandler.handleSyncWithException(request, response, e);
            return;
        }
        log.error(e.getMessage());
    } catch (ForestRuntimeException e) {
        httpRequest.abort();
        throw e;
    }
}
2.1.1、HttpclientRequestSender

HttpclientRequestSender.png

该类包含两个重要的成员变量HttpclientConnectionManagerForestRequest

protected final HttpclientConnectionManager connectionManager;

protected final ForestRequest request;

public AbstractHttpclientRequestSender(HttpclientConnectionManager connectionManager, ForestRequest request) {
    this.connectionManager = connectionManager;
    this.request = request;
}

从上述代码可以看出,对于 Apache Http ClientHttpExecutor -> RequestSender -> ConnectionManager

HttpclientRequestSender 接口仅仅只包含一个方法sendRequest,两个抽象类AsyncHttpclientRequestSenderSyncHttpclientRequestSender分别基于异步或者同步处理方式实现了该方法。

public interface HttpclientRequestSender {

    void sendRequest(ForestRequest request,
                     HttpclientResponseHandler responseHandler,
                     HttpUriRequest httpRequest,
                     LifeCycleHandler lifeCycleHandler,
                     CookieStore cookieStore,
                     Date startDate,
                     int retryCount) throws IOException;

}
2.1.2、AsyncHttpclientRequestSender

基于异步处理的HttpClient请求发送

public void sendRequest(
            final ForestRequest request, final HttpclientResponseHandler responseHandler,
            final HttpUriRequest httpRequest, LifeCycleHandler lifeCycleHandler,
            CookieStore cookieStore, Date startDate, int retryCount)  {
  			//1、从connectionManager.getHttpAsyncClient获取client对象,然后调用client.start()
        final CloseableHttpAsyncClient client = connectionManager.getHttpAsyncClient(request);
        client.start();
  			//2、调用logRequest方法记录请求日志
        final ForestResponseFactory forestResponseFactory = new HttpclientForestResponseFactory();
        logRequest(retryCount, (HttpRequestBase) httpRequest);
  			//3、调用client.execute发起请求,并设置回调函数,completed、failed、cancelled 的相关业务处理
        final Future<HttpResponse> future = client.execute(httpRequest, new FutureCallback<HttpResponse>() {
            @Override
            public void completed(final HttpResponse httpResponse) {
                ForestResponse response = forestResponseFactory.createResponse(request, httpResponse, lifeCycleHandler, null, startDate);
                if (response.isError()) {
                    ForestNetworkException networkException =
                            new ForestNetworkException("", response.getStatusCode(), response);
                    ForestRetryException retryException = new ForestRetryException(
                            networkException,  request, request.getRetryCount(), retryCount);
                    try {
                        request.getRetryer().canRetry(retryException);
                    } catch (Throwable throwable) {
                        responseHandler.handleError(response);
                        return;
                    }
                  	//3.1、如果响应错误,根据request.getRetryer().canRetry判断是否可以发起重试,然后递归调用sendRequest
                    sendRequest(request, responseHandler, httpRequest, lifeCycleHandler, cookieStore, startDate, retryCount + 1);
                    return;
                }
              	//3.2、通过lifeCycleHandler.handleSaveCookie处理cookie,
              	// 然后调用responseHandler.handleSuccess处理响应结果。
                ForestCookies cookies = getCookiesFromHttpCookieStore(cookieStore);
                lifeCycleHandler.handleSaveCookie(request, cookies);
                responseHandler.handleSuccess(response);
            }

            @Override
            public void failed(final Exception ex) {
                ForestResponse response = forestResponseFactory.createResponse(request, null, lifeCycleHandler, ex, startDate);
                ForestRetryException retryException = new ForestRetryException(
                        ex,  request, request.getRetryCount(), retryCount);
                try {
                    request.getRetryer().canRetry(retryException);
                } catch (Throwable throwable) {
                    responseHandler.handleError(response, ex);
                    return;
                }
              	//3.3、如果请求发送失败,根据request.getRetryer().canRetry判断是否可以发起重试,然后递归调用sendRequest
                sendRequest(request, responseHandler, httpRequest, lifeCycleHandler, cookieStore, startDate, retryCount + 1);
            }

            @Override
            public void cancelled() {
            }
        });
  			//4、委托给 responseHandler.handleFuture 处理响应结果
        responseHandler.handleFuture(future, startDate, forestResponseFactory);
    }
2.1.3、SyncHttpclientRequestSender

基于同步处理的HttpClient请求发送

public void sendRequest(
        ForestRequest request, HttpclientResponseHandler responseHandler,
        HttpUriRequest httpRequest, LifeCycleHandler lifeCycleHandler,
        CookieStore cookieStore, Date startDate, int retryCount)
        throws IOException {
    HttpResponse httpResponse = null;
    ForestResponse response = null;
    client = getHttpClient(cookieStore);
    ForestResponseFactory forestResponseFactory = new HttpclientForestResponseFactory();
    try {
        logRequest(retryCount, (HttpRequestBase) httpRequest);
        httpResponse = client.execute(httpRequest);
        response = forestResponseFactory.createResponse(request, httpResponse, lifeCycleHandler, null, startDate);
    } catch (IOException e) {
        httpRequest.abort();
        ForestRetryException retryException = new ForestRetryException(
                e,  request, request.getRetryCount(), retryCount);
        try {
            request.getRetryer().canRetry(retryException);
        } catch (Throwable throwable) {
            response = forestResponseFactory.createResponse(request, httpResponse, lifeCycleHandler, throwable, startDate);
            lifeCycleHandler.handleSyncWithException(request, response, e);
            return;
        }
        response = forestResponseFactory.createResponse(request, httpResponse, lifeCycleHandler, null, startDate);
        logResponse(response);
        sendRequest(request, responseHandler, httpRequest, lifeCycleHandler, cookieStore, startDate, retryCount + 1);
        return;
    } finally {
        connectionManager.afterConnect();
        if (response == null) {
            response = forestResponseFactory.createResponse(request, httpResponse, lifeCycleHandler, null, startDate);
        }
        logResponse(response);
    }
    if (response.isError()) {
        ForestNetworkException networkException =
                new ForestNetworkException("", response.getStatusCode(), response);
        ForestRetryException retryException = new ForestRetryException(
                networkException,  request, request.getRetryCount(), retryCount);
        try {
            request.getRetryer().canRetry(retryException);
        } catch (Throwable throwable) {
            responseHandler.handleSync(httpResponse, response);
            return;
        }
        sendRequest(request, responseHandler, httpRequest, lifeCycleHandler, cookieStore, startDate, retryCount + 1);
        return;
    }

    try {
        lifeCycleHandler.handleSaveCookie(request, getCookiesFromHttpCookieStore(cookieStore));
        responseHandler.handleSync(httpResponse, response);
    } catch (Exception ex) {
        if (ex instanceof ForestRuntimeException) {
            throw ex;
        }
        else {
            throw new ForestRuntimeException(ex);
        }
    }
}

2.2、AbstractOkHttp3Executor

基于OkHttp3实现Http调用的执行器,该类实现了HttpExecutor接口,最核心的方法execute

该类包含三个重要的成员变量

protected final ForestRequest request;

private final OkHttp3ConnectionManager connectionManager;

private final OkHttp3ResponseHandler okHttp3ResponseHandler;

该类默认构造方法

protected AbstractOkHttp3Executor(ForestRequest request, OkHttp3ConnectionManager connectionManager, OkHttp3ResponseHandler okHttp3ResponseHandler) {
    this.request = request;
    this.connectionManager = connectionManager;
    this.okHttp3ResponseHandler = okHttp3ResponseHandler;
}

该类核心方法

public void execute(final LifeCycleHandler lifeCycleHandler, int retryCount)

源码分析

public void execute(final LifeCycleHandler lifeCycleHandler, int retryCount) {
    //1、通过getClient方法创建 OkHttpClient 实例对象
    OkHttpClient okHttpClient = getClient(request, lifeCycleHandler);
    URLBuilder urlBuilder = getURLBuilder();
    String url = urlBuilder.buildUrl(request);

    //2、构建 Request.Builder 实例对象,并调用prepareX相关方法进行相关初始化
    Request.Builder builder = new Request.Builder().url(url);
    prepareMethod(builder);
    prepareHeaders(builder);
    prepareBody(builder, lifeCycleHandler);

    //3、构建 Request 实例对象
    final Request okRequest = builder.build();
    Call call = okHttpClient.newCall(okRequest);

    //4、构建 OkHttp3ForestResponseFactory 实例对象,并调用 logRequest 方法记录请求request对象相关日志
    final OkHttp3ForestResponseFactory factory = new OkHttp3ForestResponseFactory();
    logRequest(retryCount, okRequest, okHttpClient);
    Date startDate = new Date();
    long startTime = startDate.getTime();

    //5、判断request是否异步请求类型,然后执行不同策略
    if (request.isAsync()) {
        final OkHttp3ResponseFuture future = new OkHttp3ResponseFuture();

        //5.1、调用Call的 enqueue方法,内部设置回调函数处理 onFailure 和 onResponse
        // 在 onFailure 如果不做异常,则记录ForestResponse日志同步,递归调用 execute 本方法进行重试操作。
        // 在 onResponse 方法中,调用 logResponse 记录响应日志,同时判断ForestResponse#isSuccess 方法是否成功
        // ,否则 retryOrDoError 执行该方法进行重试,最终委托给 okHttp3ResponseHandler#handleFuture处理结果
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ForestRetryException retryException = new ForestRetryException(
                        e, request, request.getRetryCount(), retryCount);
                try {
                    request.getRetryer().canRetry(retryException);
                } catch (Throwable throwable) {
                    future.failed(e);
                    ForestResponse response = factory.createResponse(request, null, lifeCycleHandler, throwable, startDate);
                    logResponse(response);
                    lifeCycleHandler.handleError(request, response, e);
                    return;
                }
                execute(lifeCycleHandler, retryCount + 1);
            }

            @Override
            public void onResponse(Call call, Response okResponse) throws IOException {
                ForestResponse response = factory.createResponse(request, okResponse, lifeCycleHandler, null, startDate);
                logResponse(response);
                Object result = null;
                if (response.isSuccess()) {
                    if (request.getOnSuccess() != null) {
                        result = okHttp3ResponseHandler.handleSuccess(response);
                    }
                    else {
                        result = okHttp3ResponseHandler.handleSync(okResponse, response);
                    }
                    future.completed(result);
                } else {
                    retryOrDoError(response, okResponse, future, lifeCycleHandler, retryCount, startTime);
                }
            }
        });
        okHttp3ResponseHandler.handleFuture(future, startDate, factory);
    }
    //5.2、通过call#execute()方法执行处理,如果捕捉异常,同样递归重试操作
    else {
        Response okResponse = null;
        ForestResponse response = null;
        try {
            okResponse = call.execute();
        } catch (IOException e) {
            ForestRetryException retryException = new ForestRetryException(
                    e, request, request.getRetryCount(), retryCount);
            try {
                request.getRetryer().canRetry(retryException);
            } catch (Throwable throwable) {
                response = factory.createResponse(request, null, lifeCycleHandler, e, startDate);
                logResponse(response);
                lifeCycleHandler.handleSyncWithException(request, response, e);
                return;
            }
            response = factory.createResponse(request, null, lifeCycleHandler, e, startDate);
            logResponse(response);
            execute(lifeCycleHandler, retryCount + 1);
            return;
        } finally {
            if (response == null) {
                response = factory.createResponse(request, okResponse, lifeCycleHandler, null, startDate);
            }
            logResponse(response);
        }

        if (response.isError()) {
            retryOrDoError(response, okResponse, null, lifeCycleHandler, retryCount, startTime);
            return;
        }
        okHttp3ResponseHandler.handleSync(okResponse, response);
    }
}

3、HttpBackend

该类包括一个抽象类AbstractHttpBackend,并最终有两个实现类HttpclientBackendOkHttp3Backend

HttpBackend.png

public interface HttpBackend {

    String getName();

    HttpExecutor createExecutor(ForestRequest request, LifeCycleHandler lifeCycleHandler);

    void init(ForestConfiguration configuration);

    interface HttpExecutorCreator {
        HttpExecutor createExecutor(ForestConnectionManager connectionManager, ForestRequest request, LifeCycleHandler lifeCycleHandler);
    }

}

3.1、AbstractHttpBackend

该类包括两个实现类HttpclientBackendOkHttp3Backend,通过对外暴露createExecutor方法,以根据ForestRequestLifeCycleHandler,创建request请求,进而根据请求方式类型,通过从executorCreatorMap中根据请求类型,查找对应的HttpExecutor执行发送HTTP请求以及处理响应结果。

该类包含两个重要的成员变量

private volatile boolean initialized = false;

private final Map<ForestRequestType, HttpExecutorCreator> executorCreatorMap = new HashMap<>();

private final ForestConnectionManager connectionManager;

public AbstractHttpBackend(ForestConnectionManager connectionManager) {
    this.connectionManager = connectionManager;
}

核心方法createExecutor()

根据ForestRequest获取type,然后从executorCreatorMap获取对应HttpExecutorCreator,进而调用httpExecutorCreator.createExecutor。

public HttpExecutor createExecutor(ForestRequest request, LifeCycleHandler lifeCycleHandler) {
    ForestRequestType type = request.getType();
    HttpExecutorCreator httpExecutorCreator = executorCreatorMap.get(type);
    if (httpExecutorCreator == null) {
        throw new ForestRuntimeException("Http request type \"" + type.getName() + "\" is not be supported.");
    }
    HttpExecutor executor = httpExecutorCreator.createExecutor(connectionManager, request, lifeCycleHandler);
    return executor;
}

3.2、HttpclientBackend

httpclient的请求后端,实现AbstractHttpBackend抽象类的一系列抽象方法,方法内部创建不通请求类型OkHttpXXXExecutor实例。

3.3、OkHttp3Backend

okhttp的请求后端,实现AbstractHttpBackend抽象类的一系列抽象方法,方法内部创建不通请求类型OkHttpXXXExecutor实例。

4、HttpBackendSelector

该类的主要职责,通过对外暴露select方法,我们通常全局会通过forest.backend来指定选择okhttp3或者httpclient,所以该类的主要作用就是根据ForestConfiguration通过反射创建支持okhttp3或者httpclientHttpBackend实例。

static {
    BACKEND_MAP.put(HTTPCLIENT_BACKEND_NAME, HTTPCLIENT_BACKEND_CREATOR);
    BACKEND_MAP.put(OKHTTP3_BACKEND_NAME, OKHTTP3_BACKEND_CREATOR);
}

public HttpBackend select(ForestConfiguration configuration) {
    String name = configuration.getBackendName();
    if (StringUtils.isNotEmpty(name)) {
        HttpBackendCreator backendCreator = BACKEND_MAP.get(name);
        if (backendCreator == null) {
            throw new ForestRuntimeException("Http setBackend \"" + name + "\" can not be found.");
        }
        return backendCreator.create();
    }

    HttpBackend backend = null;
    backend = findOkHttp3BackendInstance();
    if (backend != null) {
        return backend;
    }
    backend = findHttpclientBackendInstance();
    if (backend != null) {
        return backend;
    }
    throw new ForestRuntimeException("Http Backed is undefined.");
}

HttpBackendCreator

通过类路径反射创建实例

static class HttpBackendCreator {

    public String className;

    public HttpBackendCreator(String className) {
        this.className = className;
    }

    public HttpBackend create() {
        try {
            Class klass = Class.forName(className);
            return (HttpBackend) klass.newInstance();
        } catch (ClassNotFoundException e) {
            throw new ForestRuntimeException(e);
        } catch (InstantiationException e) {
            throw new ForestRuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new ForestRuntimeException(e);
        }
    }
}

5、ForestConfiguration

该类的主要职责类似一个上线文对象,通过装载forest相关配置信息,同时也是相关各个组件的数据传输纽带。

configuration()

该方法用于初始化配置

/**
     * 实例化ForestConfiguration对象,并初始化默认值
     * @return 新创建的ForestConfiguration实例
     */
    public static ForestConfiguration configuration() {
        ForestConfiguration configuration = new ForestConfiguration();
        configuration.setId("forestConfiguration" + configuration.hashCode());
        configuration.setJsonConverterSelector(new JSONConverterSelector());
        configuration.setXmlConverter(new ForestJaxbConverter());
        configuration.setTextConverter();
        configuration.getConverterMap().put(ForestDataType.AUTO, new DefaultAutoConverter(configuration));
        configuration.getConverterMap().put(ForestDataType.BINARY, new DefaultBinaryConverter());
        setupJSONConverter(configuration);
        configuration.setTimeout(3000);
        configuration.setConnectTimeout(2000);
        configuration.setMaxConnections(500);
        configuration.setMaxRouteConnections(500);
        configuration.setRetryer(BackOffRetryer.class);
        configuration.setRetryCount(0);
        configuration.setMaxRetryInterval(0);
//        configuration.setSslProtocol(SSLUtils.TLS_1_2);
        configuration.registerFilter("json", JSONFilter.class);
        configuration.registerFilter("xml", XmlFilter.class);
        configuration.setLogHandler(new DefaultLogHandler());
        RequestBodyBuilder.registerBodyBuilder(CharSequence.class, new RequestBodyBuilder.StringRequestBodyBuilder());
        RequestBodyBuilder.registerBodyBuilder(String.class, new RequestBodyBuilder.StringRequestBodyBuilder());
        RequestBodyBuilder.registerBodyBuilder(File.class, new RequestBodyBuilder.FileRequestBodyBuilder());
        RequestBodyBuilder.registerBodyBuilder(byte[].class, new RequestBodyBuilder.ByteArrayRequestBodyBuilder());
        RequestBodyBuilder.registerBodyBuilder(InputStream.class, new RequestBodyBuilder.InputStreamBodyBuilder());
        RequestBodyBuilder.registerBodyBuilder(Object.class, new RequestBodyBuilder.ObjectRequestBodyBuilder());
        return configuration;
    }

createInstance()

该方法用于动态代理实例创建

/**
 * 创建请求接口的动态代理实例
 * @param clazz  请求接口类
 * @param <T>    请求接口类泛型
 * @return       动态代理实例
 */
public <T> T createInstance(Class<T> clazz) {
    ProxyFactory<T> proxyFactory = getProxyFactory(clazz);
    return proxyFactory.createInstance();
}

6、ProxyFactory

接口代理工工厂类

核心代码如下

/**
 * @author gongjun[dt_flys@hotmail.com]
 * @since 2016-03-25 18:17
 */
public class ProxyFactory<T> {

    private ForestConfiguration configuration;
    private Class<T> interfaceClass;

    public ProxyFactory(ForestConfiguration configuration, Class<T> interfaceClass) {
        this.configuration = configuration;
        this.interfaceClass = interfaceClass;
    }

    public Class<T> getInterfaceClass() {
        return interfaceClass;
    }

    public void setInterfaceClass(Class<T> interfaceClass) {
        this.interfaceClass = interfaceClass;
    }

    public T createInstance() {
        T instance = (T) configuration.getInstanceCache().get(interfaceClass);
        boolean cacheEnabled = configuration.isCacheEnabled();
        if (cacheEnabled && instance != null) {
            return instance;
        }
        synchronized (configuration.getInstanceCache()) {
            instance = (T) configuration.getInstanceCache().get(interfaceClass);
            if (cacheEnabled && instance != null) {
                return instance;
            }
            InterfaceProxyHandler<T> interfaceProxyHandler = new InterfaceProxyHandler<T>(configuration, this, interfaceClass);
            instance = (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass, ForestClientProxy.class}, interfaceProxyHandler);
            if (cacheEnabled) {
                configuration.getInstanceCache().put(interfaceClass, instance);
            }
            return instance;
        }
    }

}

7、InterfaceProxyHandler

接口代理工工厂类

InterfaceProxyHandler.png

构造函数

在构造函数中,我们可以看到同时调用了两个成员方法prepareBaseInfo()和initMethods()

public InterfaceProxyHandler(ForestConfiguration configuration, ProxyFactory proxyFactory, Class<T> interfaceClass) {
    this.configuration = configuration;
    this.proxyFactory = proxyFactory;
    this.interfaceClass = interfaceClass;
    this.interceptorFactory = configuration.getInterceptorFactory();

    try {
        defaultMethodConstructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
        if (!defaultMethodConstructor.isAccessible()) {
            defaultMethodConstructor.setAccessible(true);
        }
        defaultMethodLookup = defaultMethodConstructor.newInstance(interfaceClass, MethodHandles.Lookup.PRIVATE);
    } catch (Throwable e) {
        throw new ForestRuntimeException(e);
    }
    prepareBaseInfo();
    initMethods();
}

prepareBaseInfo方法

private void prepareBaseInfo() {
    Annotation[] annotations = interfaceClass.getAnnotations();

    for (int i = 0; i < annotations.length; i++) {
        Annotation annotation = annotations[i];
        if (annotation instanceof BaseURL) {
            BaseURL baseURLAnn = (BaseURL) annotation;
            String value = baseURLAnn.value();
            if (value == null || value.trim().length() == 0) {
                continue;
            }
            baseURL = value.trim();
            baseMetaRequest.setUrl(baseURL);
        } else {
            BaseLifeCycle baseLifeCycle = annotation.annotationType().getAnnotation(BaseLifeCycle.class);
            MethodLifeCycle methodLifeCycle = annotation.annotationType().getAnnotation(MethodLifeCycle.class);
            if (baseLifeCycle != null || methodLifeCycle != null) {
                if (baseLifeCycle != null) {
                    Class<? extends BaseAnnotationLifeCycle> interceptorClass = baseLifeCycle.value();
                    if (interceptorClass != null) {
                        BaseAnnotationLifeCycle baseInterceptor = interceptorFactory.getInterceptor(interceptorClass);
                        baseInterceptor.onProxyHandlerInitialized(this, annotation);
                    }
                }
                baseAnnotations.add(annotation);
            }
        }
    }
}

initMethods方法

扫描接口类的接口方法,然后创建ForestMethod实例,并添加到forestMethodMap中,以供其成员方法invoke供外部调用使用。

private void initMethods() {
    Method[] methods = interfaceClass.getDeclaredMethods();
    for (int i = 0; i < methods.length; i++) {
        Method method = methods[i];
        if(method.isDefault()){
            continue;
        }
        ForestMethod forestMethod = new ForestMethod(this, configuration, method);
        forestMethodMap.put(method, forestMethod);
    }
}

invoke方法

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String methodName = method.getName();
    if (method.isDefault()) {
      return invokeDefaultMethod(proxy, method, args);
    }
    if ("toString".equals(methodName) && (args == null || args.length == 0)) {
        return "{Forest Proxy Object of " + interfaceClass.getName() + "}";
    }
    if ("equals".equals(methodName) && (args != null && args.length == 1)) {
        Object obj = args[0];
        if (Proxy.isProxyClass(obj.getClass())) {
            InvocationHandler h1 = Proxy.getInvocationHandler(proxy);
            InvocationHandler h2 = Proxy.getInvocationHandler(obj);
            return h1.equals(h2);
        }
        return false;
    }
    //根据请求的接口方法,然后从forestMethodMap中查找ForestMethod实例对象,这里的forestMethodMap实际在构造函数中,通过扫描接口的接口方法然后初始化
    ForestMethod forestMethod = forestMethodMap.get(method);
    return forestMethod.invoke(args);
}

8、ForestMethod

通过代理调用的实际执行的方法对象

/**
 * 调用方法
 * @param args 调用本对象对应方法时传入的参数数组
 * @return 调用本对象对应方法结束后返回的值,任意类型的对象实例
 */
public Object invoke(Object[] args) {
    ForestRequest request = makeRequest(args);
    MethodLifeCycleHandler<T> lifeCycleHandler = new MethodLifeCycleHandler<>(
            this, onSuccessClassGenericType);
    request.setBackend(configuration.getBackend())
            .setLifeCycleHandler(lifeCycleHandler);
    lifeCycleHandler.handleInvokeMethod(request, this, args);
    // 如果返回类型为ForestRequest,直接返回请求对象
    if (ForestRequest.class.isAssignableFrom(returnClass)) {
        Type retType = getReturnType();
        if (retType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) retType;
            Type[] genTypes = parameterizedType.getActualTypeArguments();
            if (genTypes.length > 0) {
                Type targetType = genTypes[0];
                returnClass = ReflectUtils.getClassByType(targetType);
                returnType = targetType;
            } else {
                returnClass = String.class;
                returnType = String.class;
            }
        }
        return request;
    }
    return request.execute();
}

9、ForestRequest

Forest请求对象

/**
     * 执行请求发送过程
     *
     * @param backend HTTP后端,{@link HttpBackend}接口实例
     * @param lifeCycleHandler 生命周期处理器,{@link LifeCycleHandler}接口实例
     * @return 接受到请求响应后,其响应内容反序列化成对象的结果
     */
public Object execute(HttpBackend backend, LifeCycleHandler lifeCycleHandler) {
  //1、通过拦截器责任链校验当前请求
  if (interceptorChain.beforeExecute(this)) {
    //2、然后调用HttpBackend的createExecutor方法,创建HttpExecutor实例
    HttpExecutor executor  = backend.createExecutor(this, lifeCycleHandler);
    if (executor != null) {
      try {
        //3、最终调用execute方法
        executor.execute(lifeCycleHandler);
      } catch (ForestRuntimeException e) {
        throw e;
      } finally {
        executor.close();
      }
    }
  }
  return getMethodReturnValue();
}

/**
     * 执行请求发送过程
     *
     * @return 接受到请求响应后,其响应内容反序列化成对象的结果
     */
public Object execute() {
  return execute(getBackend(), getLifeCycleHandler());
}

三、归纳总结

3.1、一篇流程图

Forest-uml-flow.png

  • 1、通过ForestConfiguration调用其静态方法#createInstance(Class<T> clazz),再方法内部创建ProxyFactory<T>代理工厂实例并调用成员方法createInstance()
  • 2、在ProxyFactory<T>的方法createInstance()内部,通过调用动态代理类InterfaceProxyHandler<T>为代理接口通过动态代理方式创建接口实例。
  • 3、在动态代理类InterfaceProxyHandler<T>的默认构造函数中,获取接口类相关注解并窗户相关信息,同时获取所有接口方法然后创建ForestMethod实例对象,并添加到forestMethodMap中。
  • 4、在动态代理类InterfaceProxyHandler<T>invoke方法中,根据传过来的methodforestMethodMap获取ForestMethod实例,并调用invoke方法。方法内部业务逻辑,根据forestMethod实例创建ForestRequest对象实例,然后调用对应的execute方法。
  • 5、在ForestRequest类的成员方法execute中,根据type(分为okhttp3或者httpclient)动态创建HttpExecutor实例。
  • 6、对于httpclient,在AbstractHttpclientExecutorexecute方法中,通过委托给HttpclientRequestSender发送请求,并根据请求类型,区分异步还是同步,并根据HttpclientConnectionManager获取不同的client实例,并最终调用execute方法。
  • 7、对于okttp3,在AbstractOkHttp3Executor的execute方法中,通过Okhttp3ConnectionManager获取httpclient,然后调用其execute方法。

3.2、自我序言

之前则是自己基于apche http client 或者 okhttp3封装一个HttpUtils类似的工具类,以供系统内部调用其他应用服务提供HTTP协议接口,也有的项目则直接基于Spring提供的RestTemplate来封装相关接口。无论何种实现方式,其实我们发现这种模板化的代码还是挺普遍的。

直到遇到一个其他团队的同事,推荐了这个forest,看过了它的入门文档,然后在一个新应用服务快速集成了这个工具。带来最大的编程感受是:我们仅仅只需要为每一个三方服务定义一个接口,通过注解形式标识请求方法的出参入参,同时标识uri以及http请求方式等相关配置参数,然后把这个接口注入到你的service中,就可以直接方法接口方法了,这样看起来太简便了,代码也看起来更整洁了。

这样以来,我们就直接推荐到其他项目中,并迅速得到推广,同事们也按部就班挺顺手。借助于空闲时间,然后下载了forest的工程源码,发现这个工程源代码组织的相当优美。一个小小的工具类,通过引入大量的设计模式,使得代码非常具有美感。

然后我就逐步解读一个请求流程的相关代码,品味其代码的组织编程美感,并最终形成了这篇文章,以分享给大家。

​ ——2021年8月6日 14时27分 于 北京朝阳 HW大厦

【Forest官网】http://forest.dtflyx.com/

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值