All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.turbospaces.okhttp.OkHttpClientFactoryBean Maven / Gradle / Ivy

The newest version!
package com.turbospaces.okhttp;

import com.turbospaces.cfg.ApplicationProperties;
import com.turbospaces.okhttp.interceptors.ProxyInterceptor;
import com.turbospaces.okhttp.interceptors.RemoveSoapHeadersInterceptor;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.okhttp3.OkHttpConnectionPoolMetrics;
import io.micrometer.core.instrument.binder.okhttp3.OkHttpMetricsEventListener;
import okhttp3.ConnectionPool;
import okhttp3.Dispatcher;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.config.AbstractFactoryBean;

import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

public class OkHttpClientFactoryBean extends AbstractFactoryBean implements BeanNameAware {
    protected final ApplicationProperties props;
    protected final MeterRegistry meterRegistry;
    protected String beanName;

    public OkHttpClientFactoryBean(ApplicationProperties props, MeterRegistry meterRegistry) {
        this.props = Objects.requireNonNull(props);
        this.meterRegistry = Objects.requireNonNull(meterRegistry);
        setSingleton(true);
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }

    @Override
    public Class getObjectType() {
        return OkHttpClient.class;
    }

    public OkHttpClient.Builder getBuilder() {
        var builder = new OkHttpClient.Builder();
        var maxIdleConnections = props.TCP_CONNECTION_CLOSE_IDLE_IMMEDIATELY.get() ? 0 : 5; //add prop
        ConnectionPool connectionPool = new ConnectionPool(
                maxIdleConnections,
                props.TCP_KEEP_ALIVE_TIMEOUT.get().toMillis(),
                TimeUnit.MILLISECONDS
        );
        Dispatcher dispatcher = new Dispatcher();
        dispatcher.setMaxRequests(props.HTTP_POOL_MAX_SIZE.get());
        dispatcher.setMaxRequestsPerHost(props.HTTP_POOL_MAX_PER_ROUTE.get());

        builder.addInterceptor(new ProxyInterceptor(props))
                .addInterceptor(new RemoveSoapHeadersInterceptor())
                .retryOnConnectionFailure(true)
                .connectionPool(connectionPool)
                .dispatcher(dispatcher)
                //The read timeout is applied to both the TCP socket and for individual read IO operations.
                .readTimeout(props.TCP_SOCKET_TIMEOUT.get())
                //Sets the default connect timeout for new connections when connecting a TCP socket to the target host
                .connectTimeout(props.TCP_CONNECTION_TIMEOUT.get())
                // ~ metrics
                .eventListener(OkHttpMetricsEventListener
                        .builder(meterRegistry, "httpcomponents.httpclient.request")
                        .uriMapper(this::getUri)
                        .build());
        new OkHttpConnectionPoolMetrics(connectionPool, "okhttp.pool", Collections.emptyList(), maxIdleConnections).bindTo(meterRegistry);

        return builder;
    }

    @Override
    protected OkHttpClient createInstance() throws Exception {
        OkHttpClient.Builder builder = getBuilder();
        return builder.build();
    }

    private String getUri(Request httpRequest) {
        List mask = props.HTTP_METRICS_OUTBOUND_PATH_MASK.get();
        String uriPattern = httpRequest.header("URI_PATTERN");
        if (StringUtils.isNotEmpty(uriPattern)) {
            return uriPattern;
        }
        String uri = httpRequest.url().uri().toString();
        if (CollectionUtils.isNotEmpty(mask)) {
            Optional mapping = mask.stream().filter(p -> p.asPredicate().test(uri)).map(Pattern::pattern).findAny();
            if (mapping.isPresent()) {
                return mapping.get();
            }
        }
        return URI.create(uri).getPath();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy