'Spring AOP does not intercept Feign.Client calls

I'm trying to use Spring AOP to intercept Feign.Client calls and log request and response to my Splunk Server. All methods in my project package are intercepted as I expected but Feign.Client doesn't.

This is my AOP class:

@Component
@Aspect
public class MyAspect {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Pointcut("execution(* com.example.demo.*.*(..))")
    public void pointCutDemo(){}

    @Pointcut("execution(* feign.Client+.*(..))")
    public void pointCutFeign(){}

    @Around("pointCutDemo()")
    public void myAroundDemo(ProceedingJoinPoint joinPoint) throws Throwable {
        logger.info("calling joinpoint "+joinPoint.getSignature().getName());
        joinPoint.proceed();
    }

    @Around("pointCutFeign()")
    public void myAroundFeign(ProceedingJoinPoint joinPoint) throws Throwable {
        logger.info("calling feign joinpoint "+joinPoint.getSignature().getName());
        joinPoint.proceed();
    }
}

The method myAroundDemo is called multiple times, as I expected, but myAroundFeign is never called.

I have a simple Controller that call my interface (Feign API), this is the controller:

@RestController
public class Controller {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private ExternalAPI externalAPI;

    @GetMapping
    public String get(){
        logger.info("calling get method");
        logger.info(String.valueOf(externalAPI.listUsers()));
        return "I'm here";
    }
}

And this is my Feign Interface:

@FeignClient(url = "http://localhost:3000", name = "feign", configuration = FeignConfig.class)
public interface ExternalAPI {
    @GetMapping(value = "/menu")
    String listUsers();
}


Solution 1:[1]

@kriegaex is correct and I can't apply AOP in a non-Spring Component. But I prefer not to use pure AspectJ, so I fixed with another solution. Here are my steps to solve the problem:

1) Enabling Spring Cloud Ribbon I got the class LoadBalancerFeignClient managed by spring that implements feign.Client, so I added the dependency in pom.xml and changed my application.yml.

application.yml

myfeign:
  ribbon:
    listOfServers: localhost:3000

pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

2) In MyAspect class I intercepted the LoadBalancerFeignClient class:

@Pointcut("execution(* org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.execute(..))")
public void pointCutFeign(){}

@Around("pointCutFeign()")
public Object myAroundFeign(ProceedingJoinPoint joinPoint) throws Throwable {
    if (joinPoint.getArgs().length > 0) {
        Request request = (Request) joinPoint.getArgs()[0];
        logger.info("REQUEST >>>>>>>>>>>>");
        logger.info("URL = "+request.url());
        logger.info("METHOD = "+request.httpMethod().name());
        logger.info("BODY = "+request.requestBody().asString());
        logger.info("HEADERS = "+request.headers().toString());
    }

    Response response = (Response) joinPoint.proceed();

    logger.info("RESPONSE <<<<<<<<<<<<<<");
    logger.info("STATUS = "+response.status());
    logger.info("HEADERS = "+response.headers().toString());
    logger.info("BODY = " + IOUtils.toString(response.body().asInputStream(), "UTF-8"));
    return response;
}

Now it works very well, i got all information that i need.

Solution 2:[2]

Spring AOP only applies to Spring components. My guess would be it is not working because Feign is not a Spring component and thus out of scope for Spring AOP. If you need to apply aspects to non-Spring classes, just use full AspectJ. The Spring manual explains how to configure it via LTW (load-time weaving).

Solution 3:[3]

Feign has built in logging that you can use without AOP. If you create a feign.Logger instance and register it, it will log the request, response, and headers.

@Bean
public feign.Logger logger() {
    /* requires feign-slf4j */
    return new Slf4jLogger();
}

Logger instances provide the following features:

  • Requests are logged before they are sent to the client.
  • Responses are logged regardless of status, once they are received.
  • Retries are logged if they are triggered.

This may be a better solution if logging is all you need.

Solution 4:[4]

I also face this question . but I can not intercepted the LoadBalancerFeignClient class. i use the same code to test ,but it does not work.enter image description here

when i debug the funcution ,i find (this) point to the TraceLoadBalanceFeignClient.The LoadBalancerFeignClient ’s subclass.finally i find when i use sleuth. feign client would be create by sleuth 's feignbuilder.The pointcut will invalid

Solution 5:[5]

I have a way to get useful information when intercepting any feign client, I hope it helps someone.

@Before("@within(org.springframework.cloud.openfeign.FeignClient)")
public void logBeforeService(JoinPoint joinPoint) {
    final MethodMetadata methodMetadata = new SpringMvcContract().parseAndValidateMetadata(
                                   joinPoint.getSignature().getDeclaringType(),
                                   ((MethodSignature) joinPoint.getSignature()).getMethod());

    String requestUrl = methodMetadata.template().url();
    String methodName = methodMetadata.template().method();
    log.info("RequestUrl: {}", requestUrl);
    log.info("HttpMethod: {}", methodName);

}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 kriegaex
Solution 2 kriegaex
Solution 3 Kevin Davis
Solution 4
Solution 5