您好,登錄后才能下訂單哦!
這篇文章主要介紹了Spring Cloud Feign的示例分析,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
Feign包含了Ribbon和Hystrix,這個(gè)在實(shí)戰(zhàn)中才慢慢體會(huì)到它的意義,所謂的包含并不是Feign的jar包包含有Ribbon和Hystrix的jar包這種物理上的包含,而是Feign的功能包含了其他兩者的功能這種邏輯上的包含。簡(jiǎn)言之:Feign能干Ribbon和Hystrix的事情,但是要用Ribbon和Hystrix自帶的注解必須要引入相應(yīng)的jar包才可以。
案例一:
Eureka注冊(cè)中心:https://github.com/yejingtao/forblog/tree/master/demo-eureka-register
服務(wù)提供方:https://github.com/yejingtao/forblog/tree/master/demo-feign-freeservice
服務(wù)調(diào)用方:https://github.com/yejingtao/forblog/tree/master/demo-feign-freeconsumer
服務(wù)提供方就是個(gè)簡(jiǎn)單的EurekaClient端+web應(yīng)用,提供以下方法
@RestController @RequestMapping("/feign-service") public class HelloServiceContorller { private Logger logger = LoggerFactory.getLogger(this.getClass()); private void sleep(String methodName) { int sleepMinTime = new Random().nextInt(3000); logger.info("helloService "+methodName+" sleepMinTime: "+sleepMinTime); try { Thread.sleep(sleepMinTime); } catch (InterruptedException e) { e.printStackTrace(); } } @RequestMapping(value="/serviceGet",method=RequestMethod.GET) public String helloService(@RequestParam String name) { sleep("get"); return "HelloServiceImpl name :"+name; } @RequestMapping(value="/serviceHead", method=RequestMethod.HEAD) public String helloService(@RequestHeader String name, @RequestHeader String password) { sleep("header"); return "helloServiceHead name :"+name +" password:"+password; } @RequestMapping(value="/servicePost", method=RequestMethod.POST) public String helloService(@RequestBody UserDemo userDemo) { sleep("post"); return userDemo.toString(); } }
需要注意的以下注解不可以省略。
@RequestParam:Annotation which indicates that amethod parameter should be bound to a web request parameter
@RequestBody:Annotation indicating a methodparameter should be bound to the body of the web request.
@RequestHeader:Annotation which indicates that amethod parameter should be bound to a web request header.
如果缺少了以上注解,服務(wù)運(yùn)行起來以后雖然不會(huì)報(bào)錯(cuò),但是獲取不到入?yún)ⅰ?/p>
服務(wù)調(diào)用方項(xiàng)目:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency>
這里只依賴了Feign,沒有依賴Ribbon和Hystrix。
application.yml:
server: port: 9051 spring: application: name: demo-feign-freeconsumer eureka: client: serviceUrl: defaultZone: http://peer1:1111/eureka/,http://peer2:1112/eureka/ feign: hystrix: enabled: true #Ribbon 超時(shí)時(shí)間設(shè)置 #ribbon: # ConnectTimeout: 500 # ReadTimeout: 3000
hystrix這個(gè)配置坑了我好久我用的Spring Cloud是Dalston版本SR1,比網(wǎng)上其他材料的版本要新,因?yàn)樵谛掳姹局蠪eign對(duì)Hystrix的支持默認(rèn)是關(guān)閉的,所以要通過配置手動(dòng)打開feign.hystrix.enabled=true,這樣服務(wù)降級(jí)等功能才有效果。
Application啟動(dòng)程序
@SpringBootApplication @EnableEurekaClient @EnableFeignClients public class DemoFeignApplication { public static void main(String[] args) { SpringApplication.run(DemoFeignApplication.class, args); } }
注意這里還有個(gè)坑,我這里用的是@SpringBootApplication+@EnableEurekaClient,而不是用的@SpringCloudApplication,因?yàn)楹笳甙薂EnableCircuitBreaker,而@EnableCircuitBreaker又是屬于Hystrix包里的內(nèi)容,我的pom里并沒有引入Hystrix。所以這一點(diǎn)Spring Cloud做的還是有不足的地方,直接用@SpringCloudApplication編譯不會(huì)報(bào)錯(cuò),但是啟動(dòng)不了。當(dāng)然這里的主角還是@EnableFeignClients這個(gè)注解。
核心客戶端代碼
@FeignClient(name="demo-feign-freeservice",fallback=DemoFeignFallback.class) public interface DemoFeignService{ @RequestMapping(value="/feign-service/serviceGet",method=RequestMethod.GET) String helloService(@RequestParam("name") String name); @RequestMapping(value="/feign-service/serviceHead", method=RequestMethod.HEAD) String helloService(@RequestHeader("name") String name, @RequestHeader("password") String password); @RequestMapping(value="/feign-service/servicePost", method=RequestMethod.POST) String helloService(@RequestBody UserDemo userDemo); }
@FeignClient注解定義了該接口是一個(gè)Feign客戶端,name指定了注冊(cè)到Eureka上的服務(wù)名,fallback是服務(wù)降級(jí)后的接口實(shí)現(xiàn)類。
@RequestMapping里指定了請(qǐng)求的相對(duì)url和http請(qǐng)求方式,與服務(wù)端一一對(duì)應(yīng)。入?yún)⒗锏腀RequestParam、
@RequestBody、@RequestHeader注解比起服務(wù)端多了value屬性,這里不能省略,需要顯式的告知Feign客戶端參數(shù)要如何對(duì)應(yīng)。
降級(jí)服務(wù)代碼:
@Component public class DemoFeignFallback implements DemoFeignService{ @Override public String helloService(String name) { return "get error"; } @Override public String helloService(String name,String password) { return "head error"; } @Override public String helloService(UserDemo userDemo) { return "post error"; } }
發(fā)現(xiàn)這里的入?yún)⒗镂夜室馊サ袅薂RequestParam、@RequestBody、@RequestHeader注解,因?yàn)檫@幾個(gè)注解本質(zhì)上的意義就在于Feign在做微服務(wù)調(diào)用的時(shí)候?qū)ttp傳遞參數(shù)用的,但服務(wù)降級(jí)根本不會(huì)做http請(qǐng)求了,所以此處可以省略。
Controller代碼:
@RestController public class DemoFeignController { @Autowired private DemoFeignService demoFeignService; @RequestMapping(value="/test", method=RequestMethod.GET) public String demoServiceTest() { StringBuffer sb = new StringBuffer(); sb.append(demoFeignService.helloService("yuanyuan")); sb.append("\n"); sb.append(demoFeignService.helloService("yjt","xixihaha")); sb.append("\n"); sb.append(demoFeignService.helloService(new UserDemo("yejingtao","123456"))); return sb.toString(); } }
我們來看效果:
我們服務(wù)都沒超時(shí),3個(gè)方法全部正常,但是head請(qǐng)求沒有拿到返回值,這個(gè)是因?yàn)閔ead方式http請(qǐng)求的特性決定的,head不返回response的body體,一般用來做連通性測(cè)試來用。
再看一組:
運(yùn)氣不好head和post請(qǐng)求方法處理時(shí)間超過了2000ms,服務(wù)降級(jí),實(shí)現(xiàn)被fallback處理類取代。
在案例一中我們總有種感覺,服務(wù)提供方和服務(wù)調(diào)用方存在重復(fù)的代碼,是否可以進(jìn)行優(yōu)化?請(qǐng)看案例二。
案例二:
Eureka注冊(cè)中心:https://github.com/yejingtao/forblog/tree/master/demo-eureka-register
接口API:https://github.com/yejingtao/forblog/tree/master/demo-feign-serviceapi
服務(wù)提供方:https://github.com/yejingtao/forblog/tree/master/demo-feign-serviceimpl
服務(wù)調(diào)用方:https://github.com/yejingtao/forblog/tree/master/demo-feign-apiconsumer
案例二最大的變動(dòng)是將服務(wù)能力單獨(dú)寫到一個(gè)API的project中,調(diào)用方和提供方pom都依賴這個(gè)API。
API:
public interface HelloService { @RequestMapping(value="/feign-service/serviceGet",method=RequestMethod.GET) String helloService(@RequestParam("name") String name); @RequestMapping(value="/feign-service/serviceHead", method=RequestMethod.HEAD) String helloService(@RequestHeader("name") String name, @RequestHeader("password") String password); @RequestMapping(value="/feign-service/servicePost", method=RequestMethod.POST) String helloService(@RequestBody UserDemo userDemo); }
服務(wù)提供方:
@RestController public class HelloServiceContorller implements HelloService{ private Logger logger = LoggerFactory.getLogger(this.getClass()); private void sleep(String methodName) { int sleepMinTime = new Random().nextInt(3000); logger.info("helloService "+methodName+" sleepMinTime: "+sleepMinTime); try { Thread.sleep(sleepMinTime); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public String helloService(@RequestParam("name") String name) { sleep("get"); return "HelloServiceImpl name :"+name; } @Override public String helloService(@RequestHeader("name") String name, @RequestHeader("password") String password) { sleep("header"); return "helloServiceHead name :"+name +" password:"+password; } @Override public String helloService(@RequestBody UserDemo userDemo) { sleep("post"); return userDemo.toString(); } }
服務(wù)調(diào)用方:
@FeignClient(name="demo-feign-serviceimpl", fallback=FeignServiceFallback.class) public interface FeignService extends HelloService{ }
其它代碼基本不變,效果也一樣。
兩種風(fēng)格各有優(yōu)缺點(diǎn):freestyle的更自由,服務(wù)端新增方法不會(huì)影響客戶端代碼,缺點(diǎn)是服務(wù)能力不同步服務(wù)能力的變動(dòng)會(huì)引起異常;API格式服務(wù)端客戶端服務(wù)能力同步,但是接口的變動(dòng)需要修改兩邊的代碼,需要構(gòu)建的時(shí)候就要考慮清楚。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“Spring Cloud Feign的示例分析”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。