当前位置: 首页 > 知识库问答 >
问题:

Spring cloud@HystrixCommand不代理CompletableFuture.SupplyAsync中调用的方法

司宏伯
2023-03-14

我有一个spring组件bean,它包含一个由@HystrixCommand和FallbackMethod定义的方法methodA。bean有另一个方法methodB通过CompletableFuture.SupplyAsync(...)调用methodA。我预计Hystrix javanica会在methodA上编织方面,但是当我调试它时,我没有看到Hystrix方面被编织。

下面是一些主要的sudo代码,

测试应用程序:

package com.my.own.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages = "com.my.own.test")
public class TestApplication {
    public static void main(final String[] args) throws Exception {
        SpringApplication.run(TestApplication.class, args);
    }
}

应用程序配置:

package com.my.own.test;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
@EnableConfigurationProperties
@EnableCircuitBreaker
public class ApplicationConfig {

}
package com.my.own.test;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
@EnableAsync
public class AsyncConfig {

   @Value("${spring.threadpool.executor.core:10}")
   private int corePoolSize;

   @Value("${spring.threadpool.executor.max:20}")
   private int maxPoolSize;

   @Value("${spring.threadpool.executor.queue:1000}")
   private int queueCapacity;

   @Value("${spring.threadpool.executor.timeout:true}")
   private boolean coreThreadTimeOut;

   @Value("${spring.threadpool.executor.keepalive:30000}")
   private int keepAlive;

   @Value("${spring.threadpool.executor.prefix:ThreadPoolTaskExecutor}")
   private String threadNamePrefix;

   @Bean("taskExecutor")
   public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
       final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
       executor.setCorePoolSize(corePoolSize);
       executor.setMaxPoolSize(maxPoolSize);
       executor.setQueueCapacity(queueCapacity);
       executor.setAllowCoreThreadTimeOut(coreThreadTimeOut);
       executor.setKeepAliveSeconds(keepAlive);
       executor.setThreadNamePrefix(threadNamePrefix + "-");
       executor.initialize();

       return executor;
   }
}
package com.my.own.test.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.my.own.test.core.TestProcessor;

@RestController
public class TestController {

    private static Logger logger = LoggerFactory.getLogger(TestController.class);

    @Autowired
    TestProcessor tester;

    @RequestMapping(value = "/test", method = { RequestMethod.POST })
    public void test() {
        tester.methodB();
    }
}
package com.my.own.test.core;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

@Component
public class TestProcessor {

    @Autowired
    private ThreadPoolTaskExecutor executor;

    public void methodB() {
        final List<CompletableFuture<String>> a = new ArrayList<>();
        a.add(CompletableFuture.supplyAsync(() -> methodA(), executor));
        CompletableFuture.allOf(a.toArray(new CompletableFuture[a.size()])).join();
    }

    @HystrixCommand(fallbackMethod = "deferPushdown")
    public String methodA() {
        if (true) {
            throw new RuntimeException();
        } else {
            return "methodA";
        }
    }

    public String deferMethodA() {
        return "deferMethodA";
    }
}
Jan 03, 2018 2:55:55 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.util.concurrent.CompletionException: java.lang.RuntimeException] with root cause
java.lang.RuntimeException
    at com.my.own.test.core.TestProcessor.methodA(TestProcessor.java:40)
    at com.my.own.test.core.TestProcessor.lambda$0(TestProcessor.java:33)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

共有1个答案

邢昊焜
2023-03-14

除非您使用aspectj编织(我认为这需要对编译步骤进行特殊处理),否则spring默认使用interface/cglib编织,这只适用于从类外部调用的第一个方法,如https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-dermanding-aop-proxies中所述。

总之,如果调用methodB,则不应用方面,并且从methodB到methodA的调用不符合方面拦截的条件。要激活方面,必须直接从TestProcessor类外部调用methodB。

 类似资料:
  • 本文向大家介绍SpringCloud 中使用 Ribbon的方法详解,包括了SpringCloud 中使用 Ribbon的方法详解的使用技巧和注意事项,需要的朋友参考一下 在前两章已经给大家讲解了Ribbon负载均衡的规则 以及 如何搭建Ribbon并调用服务,那么在这一章呢 将会给大家说一说如何在SpringCloud中去使用Ribbon。在搭建之前 我们需要做一些准备工作。 1. 搭建Eure

  • 我使用的是Spring3.2.0。根据这个答案,我在我的注释控制器中有相同的方法,它实现接口, Spring配置包括, 当文件大小超过时,应该调用前面的方法,它应该自动处理异常,但它根本不会发生。即使发生异常,也不会调用方法。处理此异常的方法是什么?我是不是漏掉了什么? 在任何情况下都不会调用方法。 一般来说,如果可能的话,我希望每个控制器基(控制器级别)处理此异常。为此,一个注释方法应该只对该特

  • 我比较了CompletableFuture.SupplyAsync()在以下两种情况下的行为:我设置了一个自定义ExecutorService,或者我希望我的供应商由默认的executor(如果没有指定)执行,这两种情况是forkJoinPool.commonpool() 完成了!! 所以“done”会在主执行结束后打印出来。 但如果我用:

  • 本文向大家介绍SpringCloud用Zookeeper搭建配置中心的方法,包括了SpringCloud用Zookeeper搭建配置中心的方法的使用技巧和注意事项,需要的朋友参考一下 本文介绍了SpringCloud +Zookeeper完成配置中心,分享给大家,具有如下: 使用场景 项目配置更改不需要打包,重启 提供配置文件的可视化界面 和springcloud快速整合 为什么使用zookeep

  • 我有下面的代码块。我得到的是的catch块没有处理它。有人能告诉我如何处理下面的块抛出的异常吗?

  • 本文向大家介绍SpringCloud通用请求字段拦截处理方法,包括了SpringCloud通用请求字段拦截处理方法的使用技巧和注意事项,需要的朋友参考一下 背景 以SpringCloud构建的微服务系统为例,使用前后端分离的架构,每个系统都会提供一些通用的请求参数,例如移动端的系统版本信息、IMEI信息,Web端的IP信息,浏览器版本信息等,这些参数可能放在header里,也可以放在参数里,如果这