欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

spring cloud feign 加载流程

发布时间:2025/3/19 40 豆豆
生活随笔 收集整理的这篇文章主要介绍了 spring cloud feign 加载流程 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

一、如果只想加入feign,不要载入hystrix,则在引包时排除掉hystrix的包。

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-feign</artifactId><exclusions><exclusion><groupId>io.github.openfeign</groupId><artifactId>feign-hystrix</artifactId></exclusion></exclusions> </dependency>

并且去掉//@EnableHystrix和

@FeignClient(name = "ACCOUNT-SERVICE"/*,fallback = AccountFeignClientHystrix.class*/) public interface AccountFeignClient {

的配置,以及application中的hystrix配置

feign.hystrix.enabled=false#任务执行超时时间 #hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=400 # #hystrix.command.default.circuitBreaker.requestVolumeThreshold=2 # ##设置统计的时间窗口值的毫秒值 #hystrix.command.default.metrics.rollingStats.timeInMilliseconds=5000 # #hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000 # #hystrix.command.default.circuitBreaker.enabled=true # ## 错误比率阀值,如果错误率>=该值,circuit会被打开,并短路所有请求触发fallback。默认50 #hystrix.command.default.circuitBreaker.errorThresholdPercentage=50 # ## 线程池大小 #hystrix.threadpool.default.coreSize=3 ## 缓冲区大小, 如果为-1,则不缓冲,直接进行降级 fallback #hystrix.threadpool.default.maxQueueSize=5 ## 缓冲区大小超限的阈值,超限就直接降级 #hystrix.threadpool.default.queueSizeRejectionThreshold=2 # ## fallback执行并发量 #hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests=2ribbon.ReadTimeout=30000 ribbon.ConnectTimeout=30000 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.simplemall.micro.serv</groupId><artifactId>simplemall-proj</artifactId><version>0.0.1-SNAPSHOT</version></parent><groupId>com.simplemall.micro.serv.page</groupId><artifactId>front-app</artifactId><name>frontPage</name><description>前端页面及服务调用</description><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><java.version>1.7</java.version></properties><dependencies><!-- <dependency>--> <!-- <groupId>org.springframework.cloud</groupId>--> <!-- <artifactId>spring-cloud-starter-config</artifactId>--> <!-- </dependency>--><dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-client</artifactId><version>1.4.6</version></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-zipkin</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><!-- <dependency>--> <!-- <groupId>org.springframework.cloud</groupId>--> <!-- <artifactId>spring-cloud-starter-hystrix</artifactId>--> <!-- </dependency>--><!-- <dependency>--> <!-- <groupId>org.springframework.boot</groupId>--> <!-- <artifactId>spring-boot-starter-actuator</artifactId>--> <!-- </dependency>--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency> <!-- <dependency>--> <!-- <groupId>org.springframework.boot</groupId>--> <!-- <artifactId>spring-boot-devtools</artifactId>--> <!-- <optional>true</optional>--> <!-- </dependency>--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.datatype</groupId><artifactId>jackson-datatype-joda</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.module</groupId><artifactId>jackson-module-parameter-names</artifactId></dependency><!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.6.1</version></dependency><!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.6.1</version></dependency><dependency><groupId>com.simplemall.micro.serv.common</groupId><artifactId>common-module</artifactId><version>0.0.1-SNAPSHOT</version></dependency><!-- client request framework --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-feign</artifactId><exclusions><exclusion><groupId>io.github.openfeign</groupId><artifactId>feign-hystrix</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-ribbon</artifactId></dependency><!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt --><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.7.0</version></dependency><dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.10</version></dependency><!-- <dependency>--> <!-- <groupId>org.springframework.cloud</groupId>--> <!-- <artifactId>spring-cloud-starter-bus-amqp</artifactId>--> <!-- </dependency>--><!-- <dependency>--> <!-- <groupId>org.springframework.cloud</groupId>--> <!-- <artifactId>spring-cloud-starter-netflix-turbine</artifactId>--> <!-- </dependency>--></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Camden.SR5</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build> </project>

二、调试接口,查看代码

package com.simplemall.micro.serv.page.client;import java.util.List;//import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; //import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; //import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager; import com.simplemall.micro.serv.page.client.hystrix.AccountFeignClientHystrix; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam;import com.simplemall.micro.serv.common.bean.account.AccAddress; import com.simplemall.micro.serv.common.bean.account.Account;/*** feign与@RequestParam配合使用时,一定要写value值。* feign方法的@RequestMapping,务必与服务端方法保持一致,请求类型,请求参数,返回值等等* * TODO 可以从服务端定义一个接口层,服务实现层实现接口,调用方扩展此接口,即可完成接口定义的复用,而无须在此重新复制一次。* 但此举会导致服务端接口变动后,调用方就会直接受影响,建议事先约定好规则* * @author guooo**/ @FeignClient(name = "ACCOUNT-SERVICE"/*,fallback = AccountFeignClientHystrix.class*/) public interface AccountFeignClient {/*** 登录* * @param phone* @param password* @return*/@RequestMapping("/acc/login")public Account login(@RequestParam("phone") String phone, @RequestParam("password") String password);/*** 注册* * @param phone* @param password* @return*/@RequestMapping("/acc/signup") // @HystrixCommand(groupKey="test-thread-quarantine", // commandKey = "testThreadQuarantine", // threadPoolKey="test-thread-quarantine", // threadPoolProperties = { // @HystrixProperty(name="coreSize", value="30"), // @HystrixProperty(name="maxQueueSize", value="100"), // @HystrixProperty(name="keepAliveTimeMinutes", value="2"), // @HystrixProperty(name="queueSizeRejectionThreshold", value="15") // }, // fallbackMethod = "threadQuarantineFallback")public String signup(@RequestParam("phone") String phone, @RequestParam("password") String password);/*** get address list* * @param accountTid* @return*/@RequestMapping("/address/list/{accountTid}")// @HystrixCommand(fallbackMethod="semaphoreQuarantineFallback", // commandProperties={ // @HystrixProperty( // name= HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, // value="SEMAPHORE"), // 信号量隔离 // @HystrixProperty( // name=HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, // value="100") // 信号量最大并发数 // })public List<AccAddress> getList(@RequestParam(value = "accountTid", required = true) @PathVariable("accountTid") String accountTid); } @Slf4j @Api(value = "用户服务", tags = "用户服务接口") @RestController @RefreshScope // 使用该注解的类,会在接到SpringCloud配置中心配置刷新的时候,自动将新的配置更新到该类对应的字段中。需要重新触发加载动作可以使用POST方式请求/refresh接口,该接口位于spring-boot-starter-actuator依赖,调用前需添加否则404。 public class APIAccountController {private Logger logger = LoggerFactory.getLogger(APIAccountController.class);/*** 短信开关*/ // @Value("${switch.sms}")private boolean switchSMS = true;@Autowiredprivate AccountFeignClient accountFeignClient;@ApiOperation(value = "用户登陆")@RequestMapping(value = "acc/login", method = { RequestMethod.POST,RequestMethod.GET })public RestAPIResult<String> login(@ApiParam(value = "手机号") @RequestParam(required = true) String phone,@ApiParam(value = "密码") @RequestParam(required = true) String password, HttpSession session) {RestAPIResult<String> restAPIResult = new RestAPIResult<>();try{Account account = accountFeignClient.login(phone, password);log.info(" account:{}", JSONObject.toJSONString(account));if (StringUtils.isEmpty(account.getTid())) {restAPIResult = new RestAPIResult<String>("登陆失败,用户名或密码不正确!");restAPIResult.setRespData("kkk");} else {if (account.getTid().equalsIgnoreCase("hystrix")){restAPIResult = new RestAPIResult<String>("hystrix!");restAPIResult.setRespData("触发熔断");}else{try {// 正常情况返回jwtJSONObject subject = new JSONObject(true);subject.put("tid", account.getTid());// token此处定义12小时有效,据实际应用场景确定有效性,也可以定义刷新机制,保持用户token的使用时限String accessToken = JWTUtils.createJWT(UUIDUtils.getUUID(), subject.toJSONString(),12 * 60 * 60 * 1000);restAPIResult.setRespData(accessToken);} catch (Exception e) {logger.error("生成jwt异常{}", e);}}}logger.info("login result = {}", restAPIResult.getRespData());}catch (Exception e){restAPIResult = new RestAPIResult<String>("登陆异常!");restAPIResult.setRespData(e.getMessage());}return restAPIResult;}

查看调用堆栈,我们可以看到feignClient的代理对象为FeignInvocationHandler,真正的处理类为

SynchronousMethodHandler

 

然后client为LoadBalancerFeignClient, 这里通过LoadBalancerContext获取负载均衡器的健康实例

ILoadBalancer lb = getLoadBalancer(); Server svc = lb.chooseServer(loadBalancerKey);

 然后在AbstractLoadBalancerAwareClient.executeWithLoadBalancer进行URL中的HOST服务名替换为真实IP端口。

public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {RequestSpecificRetryHandler handler = getRequestSpecificRetryHandler(request, requestConfig);LoadBalancerCommand<T> command = LoadBalancerCommand.<T>builder().withLoadBalancerContext(this).withRetryHandler(handler).withLoadBalancerURI(request.getUri()).build();try {return command.submit(new ServerOperation<T>() {@Overridepublic Observable<T> call(Server server) {URI finalUri = reconstructURIWithServer(server, request.getUri());S requestForServer = (S) request.replaceUri(finalUri);try {return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));} catch (Exception e) {return Observable.error(e);}}}).toBlocking().single();} catch (Exception e) {Throwable t = e.getCause();if (t instanceof ClientException) {throw (ClientException) t;} else {throw new ClientException(e);}}}

 

替换完是这样

 

接着跳到FeignLoadBalancer.execute

这里配置超时,就是ribbon的超时,然后通过RetryTemplate进行一个重试框架的调用

。 

 现在进到真正的client调用

这里有一个TraceFeignClient,用来做链路追踪的。

 最终调用这个代理client对象真正完成HTTP请求。

Response response = this.delegate.execute(modifiedRequest, options);

 代理对象源码

package feign;/*** Submits HTTP {@link Request requests}. Implementations are expected to be thread-safe.*/ public interface Client {Response execute(Request request, Options options) throws IOException;public static class Default implements Client {@Overridepublic Response execute(Request request, Options options) throws IOException {HttpURLConnection connection = convertAndSend(request, options);return convertResponse(connection).toBuilder().request(request).build();}

 执行堆栈 

 这里已经返回结果了

HttpResponse 

最后外层返回结果

 

总结

以上是生活随笔为你收集整理的spring cloud feign 加载流程的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。