Spring AOP不会拦截Feign.Client调用

时间:2019-06-20 22:01:29

标签: aop spring-aop spring-cloud-feign feign

我正在尝试使用Spring AOP拦截Feign.Client调用并记录对Splunk Server的请求和响应。我的项目包中的所有方法均按我的预期被拦截,但Feign.Client未被拦截。

这是我的AOP课:

@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();
    }
}

如我所料,方法myAroundDemo被多次调用,但从未调用myAroundFeign

我有一个简单的Controller调用我的接口(Feign API),这就是控制器:

@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";
    }
}

这是我的伪装界面:

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

4 个答案:

答案 0 :(得分:1)

Spring AOP仅适用于Spring组件。我的猜测是它不起作用,因为Feign不是Spring组件,因此超出了Spring AOP的范围。如果您需要将方面应用于非Spring类,则只需使用完整的AspectJ。 Spring手册介绍了如何configure it via LTW (load-time weaving)

答案 1 :(得分:1)

@kriegaex是正确的,我不能在非Spring组件中应用AOP。但是我不想使用纯粹的AspectJ,所以我使用了另一个解决方案。这是我解决问题的步骤:

1)启用Spring Cloud Ribbon我获得了由LoadBalancerFeignClient的spring管理的类feign.Client,因此我在pom.xml中添加了依赖项并更改了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)在MyAspect类中,我拦截了LoadBalancerFeignClient类:

@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;
}

现在效果很好,我得到了我需要的所有信息。

答案 2 :(得分:0)

我也面临这个问题。但是我无法截获LoadBalancerFeignClient类。我使用相同的代码进行测试,但无法正常工作。enter image description here

当我调试功能时,我发现(指向)TraceLoadBalanceFeignClient。LoadBalancerFeignClient的子类。最后我发现使用侦探功能时。假冒客户将由sleuth的feignbuilder创建。切入点将无效

答案 3 :(得分:0)

Feign内置了无需AOP即可使用的日志记录。如果创建feign.Logger实例并进行注册,它将记录请求,响应和标头。

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

Logger实例提供以下功能:

  • 在将请求发送到客户端之前,已对其进行记录。
  • 一旦收到响应,无论状态如何,都会记录响应。
  • 重试如果被触发则被记录。

如果只需要日志记录,这可能是一个更好的解决方案。