我有一个spring组件bean,它包含由@HystrixCommand和fallbackMethod定义的方法 methodA 。 bean有另一种方法 methodB 通过CompletableFuture.supplyAsync(...)调用 methodA 。我希望Hystrix javanica会在 methodA 上编织方面,但是当我调试它时,我没有看到hystrix方面被编织。
以下是一些主要的sudo代码,
TestApplication :
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;
}
}
的TestController :
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();
}
}
TestProcessor :
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)
P.S。 从输出中,methodA不是从hystrix方面调用的,而是由lambda直接调用的。这是Hystrix或javanica的问题吗?如果您知道解决方案,请分享。我很感激。
答案 0 :(得分:1)
除非你正在使用aspectj编织(我认为需要特殊处理编译步骤),spring默认使用interface / cglib编织,它只适用于从类外部调用的第一个方法,如{{ 3}}。
总之,如果调用methodB,则不应用任何方面,并且从methodB到methodA的调用不适用于方面拦截。 要激活方面,您必须直接从TestProcessor类外部调用methodB。