JDK 之 HttpClientjdk11

HttpClient 简介

java.net.http.HttpClient 是 jdk11 中正式启用的一个 http 工具类其实早在 jdk9 的时候就已经存在了,只是处于孵化期),官方寓意为想要取代 HttpURLConnection 和 Apache HttpClient 等比较古老的开发工具。

新增的 HttpClient 截止到目前2019年3月)为止其实网络资料还比较少,笔者只是根据一些博文和官方 Demo 自己摸索了一下,做了下总结。

由于是 jdk11 中才正式使用的工具类,距离开发者还很遥远,所以对于源码笔者暂不打算深挖,浅浅的理解怎么使用就行

一、HttpClient在 Apache HttpClient 中,一般会创建一个 HttpClient 对象来作为门面。java.net.http.HttpClient 的逻辑也差不多,只是创建方式更加时髦了:

//创建 builder
HttpClient.Builder builder = HttpClient.newBuilder);

//链式调用
HttpClient client = builder

//http 协议版本 1.1 或者 2
.versionHttpClient.Version.HTTP_2) //.versionHttpClient.Version.HTTP_1_1)

//连接超时时间,单位为毫秒
.connectTimeoutDuration.ofMillis5000)) //.connectTimeoutDuration.ofMinutes1))

//连接完成之后的转发策略
.followRedirectsHttpClient.Redirect.NEVER) //.followRedirectsHttpClient.Redirect.ALWAYS)

//指定线程池
.executorExecutors.newFixedThreadPool5))

//认证,默认情况下 Authenticator.getDefault) 是 null 值,会报错
//.authenticatorAuthenticator.getDefault))

//代理地址
//.proxyProxySelector.ofnew InetSocketAddress"http://www.baidu.com", 8080)))

//缓存,默认情况下 CookieHandler.getDefault) 是 null 值,会报错
//.cookieHandlerCookieHandler.getDefault))

//创建完成
.build);

在 builder) 方法中,最终会调用到 HttpClientImpl 的构造器,完成 HttpClient 的创建工作:

    //HttpClientImpl.class
    private HttpClientImplHttpClientBuilderImpl builder,
                           SingleFacadeFactory facadeFactory) {
        //CLIENT_IDS 是 AtomicLong 类型的变量,使用 incrementAndGet) 方法实现自增长的 id
        id = CLIENT_IDS.incrementAndGet);
        //记录下存有 id 的字符串
        dbgTag = "HttpClientImpl" + id + ")";

        //ssl 认证
        if builder.sslContext == null) {
            try {
                sslContext = SSLContext.getDefault);
            } catch NoSuchAlgorithmException ex) {
                throw new InternalErrorex);
            }
        } else {
            sslContext = builder.sslContext;
        }

        //线程池,没有的话就默认创建一个
        Executor ex = builder.executor;
        if ex == null) {
            ex = Executors.newCachedThreadPoolnew DefaultThreadFactoryid));
            isDefaultExecutor = true;
        } else {
            isDefaultExecutor = false;
        }
        delegatingExecutor = new DelegatingExecutorthis::isSelectorThread, ex);
        facadeRef = new WeakReference<>facadeFactory.createFacadethis));

        //处理 http 2 的 client 类
        client2 = new Http2ClientImplthis);‘
        //缓存操作
        cookieHandler = builder.cookieHandler;
        //超时时间
        connectTimeout = builder.connectTimeout;
        //转发策略,默认为 NEVER
        followRedirects = builder.followRedirects == null ?
                Redirect.NEVER : builder.followRedirects;
        //代理设置
        this.userProxySelector = Optional.ofNullablebuilder.proxy);
        this.proxySelector = userProxySelector
                .orElseGetHttpClientImpl::getDefaultProxySelector);
        if debug.on))
            debug.log"proxySelector is %s user-supplied=%s)",
                    this.proxySelector, userProxySelector.isPresent));
        //认证设置
        authenticator = builder.authenticator;
        //设置 http 协议版本
        if builder.version == null) {
            version = HttpClient.Version.HTTP_2;
        } else {
            version = builder.version;
        }
        if builder.sslParams == null) {
            sslParams = getDefaultParamssslContext);
        } else {
            sslParams = builder.sslParams;
        }
        //连接线程池
        connections = new ConnectionPoolid);
        connections.start);
        timeouts = new TreeSet<>);

        //SelectorManager 本质上是 Thread 类的封装
        //selmgr 会开启一条线程,HttpClient 的主要逻辑运行在此线程中
        //所以说 HttpClient 是非阻塞的,因为并不跑在主线程中
        try {
            selmgr = new SelectorManagerthis);
        } catch IOException e) {
            throw new InternalErrore);
        }
        //设置为守护线程
        selmgr.setDaemontrue);
        filters = new FilterFactory);
        initFilters);
        assert facadeRef.get) != null;
    }

主要是一些储存操作,大致理解即可,不细究。

二、HttpRequest

HttpRequest 是发起请求的主体配置:

//创建 builder
HttpRequest.Builder reBuilder = HttpRequest.newBuilder);

//链式调用
HttpRequest request = reBuilder

//存入消息头
//消息头是保存在一张 TreeMap 里的
.header"Content-Type", "application/json")

//http 协议版本
.versionHttpClient.Version.HTTP_2)

//url 地址
.uriURI.create"http://openjdk.java.net/"))

//超时时间
.timeoutDuration.ofMillis5009))

//发起一个 post 消息,需要存入一个消息体
.POSTHttpRequest.BodyPublishers.ofString"hello"))

//发起一个 get 消息,get 不需要消息体
//.GET)

//method...) 方法是 POST...) 和 GET...) 方法的底层,效果一样
//.method"POST",HttpRequest.BodyPublishers.ofString"hello"))

//创建完成
.build);

三、发送

发起请求:

    HttpResponse<String> response =
            client.sendrequest, HttpResponse.BodyHandlers.ofString));
这是同步式的发起请求方式,先来看一下它的实现:
   public <T> HttpResponse<T> sendHttpRequest req, BodyHandler<T> responseHandler)
            throws IOException, InterruptedException{
        CompletableFuture<HttpResponse<T>> cf = null;
        try {
            //调用 sendAsync...) 方法异步地完成主逻辑,并获取 Future
            cf = sendAsyncreq, responseHandler, null, null);
            return cf.get);

      //这之后的所有代码都是在进行异常捕捉,所以可以忽略
        } catch InterruptedException ie) {
            if cf != null )
                cf.canceltrue);
            throw ie;
        } catch ExecutionException e) {
            final Throwable throwable = e.getCause);
            final String msg = throwable.getMessage);

            if throwable instanceof IllegalArgumentException) {
                throw new IllegalArgumentExceptionmsg, throwable);
            } else if throwable instanceof SecurityException) {
                throw new SecurityExceptionmsg, throwable);
            } else if throwable instanceof HttpConnectTimeoutException) {
                HttpConnectTimeoutException hcte = new HttpConnectTimeoutExceptionmsg);
                hcte.initCausethrowable);
                throw hcte;
            } else if throwable instanceof HttpTimeoutException) {
                throw new HttpTimeoutExceptionmsg);
            } else if throwable instanceof ConnectException) {
                ConnectException ce = new ConnectExceptionmsg);
                ce.initCausethrowable);
                throw ce;
            } else if throwable instanceof IOException) {
                throw new IOExceptionmsg, throwable);
            } else {
                throw new IOExceptionmsg, throwable);
            }
        }
    }

本质上是使用了异步实现方法 sendAsync…)。

在 Demo 中也可以直接使用:

    //返回的是 future,然后通过 future 来获取结果
    CompletableFuture<String> future =
            client.sendAsyncrequest, HttpResponse.BodyHandlers.ofString))
                    .thenApplyHttpResponse::body);
    //阻塞线程,从 future 中获取结果
    String body = future.get);

  

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注