Spring Cloud提供了Ribbon和Feign作為客戶端的負載均衡。
前面使用了Ribbon做客戶端負載均衡,使用Hystrix做容錯保護,這兩者被作為基礎工具類框架被廣泛地應用在各個微服務的實現中。SpringCloudFeign是將兩者做了更高層次的封裝以簡化開發。它基於Netfix Feign實現,整合了SpringCloud Ribbon和SpringCloud Hystrix,除了提供這兩者的強大功能外,還提供了一種聲明是的Web服務客戶端定義的方式。SpringCloud Feign在NetFixFeign的基礎上擴展了對SpringMVC注解的支持,在其實現下,我們只需創建一個接口並用注解的方式來配置它,即可完成對服務提供方的接口綁定。簡化了SpringCloud Ribbon自行封裝服務調用客戶端的開發量。
在Spring Cloud下,使用Ribbon直接注入一個RestTemplate對象即可,此RestTemplate已做好負載均衡的配置;而使用Feign只需定義個注解,有@FeignClient注解的接口,然后使用@RequestMapping注解在方法上映射遠程的REST服務,此方法也是做好了負載均衡配置。
示例一:在Spring cloud Feign中客戶端負載均衡是通過Spring cloud Ribbon實現的,下面演示通過Feign實現負載均衡。
新建一個spring-boot工程,取名為feign-consumer,在它的pom文件引入Feign的起步依賴spring-cloud-starter-feign、Eureka的起步依賴spring-cloud-starter-eureka、Web的起步依賴spring-boot-starter-web,pom代碼如下:
<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> <groupId>com.dxz</groupId> <artifactId>feign-consumer</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.5.RELEASE</version> <!--配合spring cloud版本 --> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <!--設置字符編碼及java版本 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <!--增加eureka-server的依賴 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> <!--增加feign的依賴 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> <!--用於測試的,本例可省略 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <!--依賴管理,用於管理spring-cloud的依賴 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-parent</artifactId> <version>Brixton.SR3</version> <!--官網為Angel.SR4版本,但是我使用的時候總是報錯 --> <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>
在工程的配置文件application.yml文件,指定程序名、端口號、服務注冊地址,代碼如下:
spring.application.name=compute-consume-feign
server.port=2231
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
在程序的啟動類,加上@EnableFeignClients注解開啟Feign的功能:
package com.dxz.feign; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.feign.EnableFeignClients; @SpringBootApplication @EnableFeignClients @EnableDiscoveryClient public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } }
定義一個feign接口,通過@ FeignClient(“服務名”),來指定調用哪個服務。比如在代碼中調用了遠程服務的接口,代碼如下:
package com.dxz.feign.remote; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; @FeignClient("compute-service") public interface HelloService { @RequestMapping(value="/add", method = RequestMethod.GET) String hello(@RequestParam("a") Integer a, @RequestParam("b") Integer b, @RequestParam("sn") Integer sn); }
在Web層的controller層,對外暴露一個的API接口,通過上面定義的Feign客戶端來消費服務。代碼如下:
package com.dxz.feign.service; import java.util.concurrent.atomic.AtomicInteger; 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.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.dxz.feign.remote.HelloService; @RestController public class AddConsumerController { @Autowired HelloService helloService; private AtomicInteger sn = new AtomicInteger(0); @RequestMapping(value="/feign-consumer", method = RequestMethod.GET) public String helloConsumer(@RequestParam Integer a, @RequestParam Integer b) { return helloService.hello(a, b, sn.incrementAndGet()); } }
啟動程序,多次訪問http://127.0.0.1:2231/feign-consumer?a=1&b=3,瀏覽器顯示:
再觀察日志,可以得到之前使用Ribbon時一樣的結果,對服務提供方實現了均衡負載。
二、在Spring cloud Feign同時融合了Spring Cloud Hystrix,下面演示通過Feign實現熔斷功能。
新增一個服務降級處理類:
package com.dxz.feign.remote; import org.springframework.stereotype.Service; @Service public class HelloServiceFallback implements HelloService { @Override public String hello(Integer a, Integer b, Integer sn) { System.out.println("HelloServiceFallback"); return "fallback"; } }
在服務綁定接口HelloService中,通過@FeignClient注解的fallback屬性來指定服務降級處理類:
package com.dxz.feign.remote; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import com.dxz.feign.DisableHystrixConfiguration; @FeignClient(name="compute-service", fallback=HelloServiceFallback.class) //@FeignClient(name="compute-service",configuration=DisableHystrixConfiguration.class) public interface HelloService { @RequestMapping(value="/add", method = RequestMethod.GET) String hello(@RequestParam("a") Integer a, @RequestParam("b") Integer b, @RequestParam("sn") Integer sn); }
測試: