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

问题描述 投票:0回答:1

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

这是一些主要的伪代码,

测试应用程序:

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

ApplicationConfiguration:

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 {

}

AsyncConfig:

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)

附:从输出中,methodA不是从hystrix方面调用的,而是由lambda直接调用的。这是Hystrix或javanica的问题吗?如果您知道解决方案,请分享。我很感激。

spring java-8 spring-cloud java.util.concurrent hystrix
1个回答
1
投票

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

总之,如果调用methodB,则不应用任何方面,并且从methodB到methodA的调用不适用于方面拦截。要激活方面,您必须直接从TestProcessor类外部调用methodB。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.