spring cloud feign 加载流程
一、如果只想加入feign,不要載入hystrix,則在引包時(shí)排除掉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#任務(wù)執(zhí)行超時(shí)時(shí)間 #hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=400 # #hystrix.command.default.circuitBreaker.requestVolumeThreshold=2 # ##設(shè)置統(tǒng)計(jì)的時(shí)間窗口值的毫秒值 #hystrix.command.default.metrics.rollingStats.timeInMilliseconds=5000 # #hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000 # #hystrix.command.default.circuitBreaker.enabled=true # ## 錯(cuò)誤比率閥值,如果錯(cuò)誤率>=該值,circuit會(huì)被打開(kāi),并短路所有請(qǐng)求觸發(fā)fallback。默認(rèn)50 #hystrix.command.default.circuitBreaker.errorThresholdPercentage=50 # ## 線程池大小 #hystrix.threadpool.default.coreSize=3 ## 緩沖區(qū)大小, 如果為-1,則不緩沖,直接進(jìn)行降級(jí) fallback #hystrix.threadpool.default.maxQueueSize=5 ## 緩沖區(qū)大小超限的閾值,超限就直接降級(jí) #hystrix.threadpool.default.queueSizeRejectionThreshold=2 # ## fallback執(zhí)行并發(fā)量 #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>前端頁(yè)面及服務(wù)調(diào)用</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>二、調(diào)試接口,查看代碼
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配合使用時(shí),一定要寫value值。* feign方法的@RequestMapping,務(wù)必與服務(wù)端方法保持一致,請(qǐng)求類型,請(qǐng)求參數(shù),返回值等等* * TODO 可以從服務(wù)端定義一個(gè)接口層,服務(wù)實(shí)現(xiàn)層實(shí)現(xiàn)接口,調(diào)用方擴(kuò)展此接口,即可完成接口定義的復(fù)用,而無(wú)須在此重新復(fù)制一次。* 但此舉會(huì)導(dǎo)致服務(wù)端接口變動(dòng)后,調(diào)用方就會(huì)直接受影響,建議事先約定好規(guī)則* * @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);/*** 注冊(cè)* * @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"), // 信號(hào)量隔離 // @HystrixProperty( // name=HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, // value="100") // 信號(hào)量最大并發(fā)數(shù) // })public List<AccAddress> getList(@RequestParam(value = "accountTid", required = true) @PathVariable("accountTid") String accountTid); } @Slf4j @Api(value = "用戶服務(wù)", tags = "用戶服務(wù)接口") @RestController @RefreshScope // 使用該注解的類,會(huì)在接到SpringCloud配置中心配置刷新的時(shí)候,自動(dòng)將新的配置更新到該類對(duì)應(yīng)的字段中。需要重新觸發(fā)加載動(dòng)作可以使用POST方式請(qǐng)求/refresh接口,該接口位于spring-boot-starter-actuator依賴,調(diào)用前需添加否則404。 public class APIAccountController {private Logger logger = LoggerFactory.getLogger(APIAccountController.class);/*** 短信開(kāi)關(guān)*/ // @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 = "手機(jī)號(hào)") @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("觸發(fā)熔斷");}else{try {// 正常情況返回jwtJSONObject subject = new JSONObject(true);subject.put("tid", account.getTid());// token此處定義12小時(shí)有效,據(jù)實(shí)際應(yīng)用場(chǎng)景確定有效性,也可以定義刷新機(jī)制,保持用戶token的使用時(shí)限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;}查看調(diào)用堆棧,我們可以看到feignClient的代理對(duì)象為FeignInvocationHandler,真正的處理類為
SynchronousMethodHandler?
然后client為L(zhǎng)oadBalancerFeignClient, 這里通過(guò)LoadBalancerContext獲取負(fù)載均衡器的健康實(shí)例
ILoadBalancer lb = getLoadBalancer(); Server svc = lb.chooseServer(loadBalancerKey);?然后在AbstractLoadBalancerAwareClient.executeWithLoadBalancer進(jìn)行URL中的HOST服務(wù)名替換為真實(shí)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
這里配置超時(shí),就是ribbon的超時(shí),然后通過(guò)RetryTemplate進(jìn)行一個(gè)重試框架的調(diào)用
。?
?現(xiàn)在進(jìn)到真正的client調(diào)用
這里有一個(gè)TraceFeignClient,用來(lái)做鏈路追蹤的。
?最終調(diào)用這個(gè)代理client對(duì)象真正完成HTTP請(qǐng)求。
Response response = this.delegate.execute(modifiedRequest, options);?代理對(duì)象源碼
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();}?執(zhí)行堆棧?
?這里已經(jīng)返回結(jié)果了
HttpResponse?
最后外層返回結(jié)果
?
總結(jié)
以上是生活随笔為你收集整理的spring cloud feign 加载流程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: springcloud ribbon r
- 下一篇: springcloud feign 加上