javaspringaopspring-aopfeign

AOP pointcut is not working with Feign client


In my project I have a Feign client extending API interface generated from OpenAPI spec:

@FeignClient(name = "customerClient", url = "${spring.microservice.tenant-service-gateway.host}", configuration = FeignConfiguration.class)
public interface CustomerClient extends CustomersApi {

}

FeignConfiguration introduces retry config for 500 response code:

@Configuration
@EnableAspectJAutoProxy
public class FeignConfiguration {

    @Bean
    public Retryer httpResponseCodeRetryer(
            @Value("${feign.max-attempt-count}") int retryCount,
            @Value("${feign.retry-period-seconds}") int retryPeriod
    ) {
        return new Retryer.Default(TimeUnit.SECONDS.toMillis(retryPeriod), TimeUnit.SECONDS.toMillis(3L), retryCount);
    }

    @Bean
    public ErrorDecoder httpCodeErrorDecoder() {
        return new HttpCodeErrorDecoder();
    }

    static class HttpCodeErrorDecoder implements ErrorDecoder {

        @Override
        public Exception decode(String methodKey, Response response) {
            var exception = feign.FeignException.errorStatus(methodKey, response);
            int status = response.status();
            if (status == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
                return new RetryableException(
                        response.status(),
                        exception.getMessage(),
                        response.request().httpMethod(),
                        exception,
                        null,
                        response.request());
            }
            return exception;
        }
    }
}

What I want is to add retry functionality for 202 response code either. To achieve this I add this pointcut:

@Aspect
public class AfterReturningExample {

    @Around("execution(* com.project.client.CustomerClient.*(..))")
    public Object customerClient(ProceedingJoinPoint pjp) throws Throwable {
        var proceed = pjp.proceed();
        //some logic here
        return proceed;
    }
}

I've tried to solve this by adding pointcut for the methods of CustomersApi like this:

@Around("execution(* com.project.api.CustomersApi+.*(..))")
public Object customerApi(ProceedingJoinPoint pjp) throws Throwable {
  var proceed = pjp.proceed();
  //some logic here
  return proceed;
}

Solution

  • If there is only an @Aspect on your class it won't be detected and as such nothing will be applied as Spring AOP doesn't see it.

    You can add @Component to your @Aspect annotated class which will make it available to Spring.

    @Component
    @Aspect
    public class AfterReturningExample { ... }
    

    Another option is to write an includeFilter in an @ComponentScan to include all classes annotated with @Aspect.

    @SpringBootApplication
    @ComponentScan(includeFilter= { @Filter(type = FilterType.ANNOTATION, value=org.aspectj.lang.annotation.Aspect )}
    

    With this classes annotated with @Aspect (and not with @Component) will be included as well.

    Either way will work.