feign.AsyncFeign Maven / Gradle / Ivy
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign;
import feign.InvocationHandlerFactory.MethodHandler;
import feign.Logger.Level;
import feign.Request.Options;
import feign.Target.HardCodedTarget;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.codec.ErrorDecoder;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;
/**
* Enhances {@link Feign} to provide support for asynchronous clients. Context (for example for
* session cookies or tokens) is explicit, as calls for the same session may be done across several
* threads.
*
* {@link Retryer} is not supported in this model, as that is a blocking API.
* {@link ExceptionPropagationPolicy} is made redundant as {@link RetryableException} is never
* thrown.
* Alternative approaches to retrying can be handled through {@link AsyncClient clients}.
*
* Target interface methods must return {@link CompletableFuture} with a non-wildcard type. As the
* completion is done by the {@link AsyncClient}, it is important that any subsequent processing on
* the thread be short - generally, this should involve notifying some other thread of the work to
* be done (for example, creating and submitting a task to an {@link ExecutorService}).
*/
@Experimental
public final class AsyncFeign {
public static AsyncBuilder builder() {
return new AsyncBuilder<>();
}
/**
* @deprecated use {@link #builder()} instead.
*/
@Deprecated()
public static AsyncBuilder asyncBuilder() {
return builder();
}
private static class LazyInitializedExecutorService {
private static final ExecutorService instance =
Executors.newCachedThreadPool(
r -> {
final Thread result = new Thread(r);
result.setDaemon(true);
return result;
});
}
public static class AsyncBuilder extends BaseBuilder, AsyncFeign> {
private AsyncContextSupplier defaultContextSupplier = () -> null;
private AsyncClient client = new AsyncClient.Default<>(
new Client.Default(null, null), LazyInitializedExecutorService.instance);
private MethodInfoResolver methodInfoResolver = MethodInfo::new;
@Deprecated
public AsyncBuilder defaultContextSupplier(Supplier supplier) {
this.defaultContextSupplier = supplier::get;
return this;
}
public AsyncBuilder client(AsyncClient client) {
this.client = client;
return this;
}
public AsyncBuilder methodInfoResolver(MethodInfoResolver methodInfoResolver) {
this.methodInfoResolver = methodInfoResolver;
return this;
}
@Override
public AsyncBuilder mapAndDecode(ResponseMapper mapper, Decoder decoder) {
return super.mapAndDecode(mapper, decoder);
}
@Override
public AsyncBuilder decoder(Decoder decoder) {
return super.decoder(decoder);
}
@Override
@Deprecated
public AsyncBuilder decode404() {
return super.decode404();
}
@Override
public AsyncBuilder dismiss404() {
return super.dismiss404();
}
@Override
public AsyncBuilder errorDecoder(ErrorDecoder errorDecoder) {
return super.errorDecoder(errorDecoder);
}
@Override
public AsyncBuilder doNotCloseAfterDecode() {
return super.doNotCloseAfterDecode();
}
@Override
public AsyncBuilder decodeVoid() {
return super.decodeVoid();
}
public AsyncBuilder defaultContextSupplier(AsyncContextSupplier supplier) {
this.defaultContextSupplier = supplier;
return this;
}
public T target(Class apiType, String url) {
return target(new HardCodedTarget<>(apiType, url));
}
public T target(Class apiType, String url, C context) {
return target(new HardCodedTarget<>(apiType, url), context);
}
public T target(Target target) {
return build().newInstance(target);
}
public T target(Target target, C context) {
return build().newInstance(target, context);
}
@Override
public AsyncBuilder logLevel(Level logLevel) {
return super.logLevel(logLevel);
}
@Override
public AsyncBuilder contract(Contract contract) {
return super.contract(contract);
}
@Override
public AsyncBuilder logger(Logger logger) {
return super.logger(logger);
}
@Override
public AsyncBuilder encoder(Encoder encoder) {
return super.encoder(encoder);
}
@Override
public AsyncBuilder queryMapEncoder(QueryMapEncoder queryMapEncoder) {
return super.queryMapEncoder(queryMapEncoder);
}
@Override
public AsyncBuilder options(Options options) {
return super.options(options);
}
@Override
public AsyncBuilder requestInterceptor(RequestInterceptor requestInterceptor) {
return super.requestInterceptor(requestInterceptor);
}
@Override
public AsyncBuilder requestInterceptors(Iterable requestInterceptors) {
return super.requestInterceptors(requestInterceptors);
}
@Override
public AsyncBuilder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) {
return super.invocationHandlerFactory(invocationHandlerFactory);
}
@Override
public AsyncFeign internalBuild() {
AsyncResponseHandler responseHandler =
(AsyncResponseHandler) Capability.enrich(
new AsyncResponseHandler(
logLevel,
logger,
decoder,
errorDecoder,
dismiss404,
closeAfterDecode, decodeVoid, responseInterceptorChain()),
AsyncResponseHandler.class,
capabilities);
final MethodHandler.Factory methodHandlerFactory =
new AsynchronousMethodHandler.Factory<>(
client, retryer, requestInterceptors,
responseHandler, logger, logLevel,
propagationPolicy, methodInfoResolver,
new RequestTemplateFactoryResolver(encoder, queryMapEncoder),
options, decoder, errorDecoder);
final ReflectiveFeign feign =
new ReflectiveFeign<>(contract, methodHandlerFactory, invocationHandlerFactory,
defaultContextSupplier);
return new AsyncFeign<>(feign);
}
}
private final ReflectiveFeign feign;
private AsyncFeign(ReflectiveFeign feign) {
this.feign = feign;
}
public T newInstance(Target target) {
return feign.newInstance(target);
}
public T newInstance(Target target, C context) {
return feign.newInstance(target, context);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy