在前面的文章中能够发现当咱们经过RestTemplate调用其它服务的API时,所须要的参数须在请求的URL中进行拼接,若是参数少的话或许咱们还能够忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,而且显得好傻。html
那么有没有更好的解决方案呢?答案是肯定的有,Netflix已经为咱们提供了一个框架:Feign。java
Feign是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单。Feign提供了HTTP请求的模板,经过编写简单的接口和插入注解,就能够定义好HTTP请求的参数、格式、地址等信息。web
而Feign则会彻底代理HTTP请求,咱们只须要像调用方法同样调用它就能够完成服务请求及相关处理。Feign整合了Ribbon和Hystrix(关于Hystrix咱们后面再讲),可让咱们再也不须要显式地使用这两个组件。spring
总起来讲,Feign具备以下特性:浏览器
这看起来有点像咱们springmvc模式的Controller层的RequestMapping映射。这种模式是咱们很是喜欢的。Feign是用@FeignClient来映射服务的。mvc
首先第一步,在原来的基础上新建一个Feign模块,接着引入相关依赖,引入Feign依赖,会自动引入Hystrix依赖的,以下:app
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> <version>1.4.0.RELEASE</version> </dependency>
application.yml配置以下:负载均衡
server: port: 8083 spring: application: name: feign-consumer eureka: client: service-url: defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/
接着在前面文章中的的的两个provider1和provider2两个模块的服务新增几个方法,以下代码所示:框架
/** * Created by cong on 2018/5/8. */ @RestController public class HelloController { @RequestMapping("/hello") public String hello(){ System.out.println("访问来1了......"); return "hello1"; } @RequestMapping("/hjcs") public List<String> laowangs(String ids){ List<String> list = new ArrayList<>(); list.add("laowang1"); list.add("laowang2"); list.add("laowang3"); return list; } //新增的方法 @RequestMapping(value = "/hellol", method= RequestMethod.GET) public String hello(@RequestParam String name) { return "Hello " + name; } @RequestMapping(value = "/hello2", method= RequestMethod.GET) public User hello(@RequestHeader String name, @RequestHeader Integer age) { return new User(name, age); } @RequestMapping(value = "/hello3", method = RequestMethod.POST) public String hello (@RequestBody User user) { return "Hello "+ user. getName () + ", " + user. getAge (); } }
接着是上面代码所需用到的User类,代码以下:异步
/** * Created by cong 2017/12/2. */ public class User { private String name; private Integer age; //序列化传输的时候必需要有空构造方法,否则会出错 public User() { } public User(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
接下来用Feign的@FeignClient(“服务名称”)映射服务调用。代码以下:
package hjc; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.*; /** * Created by cong on 2018/5/17. */ //configuration = xxx.class 这个类配置Hystrix的一些精确属性
//value=“你用到的服务名称”
@FeignClient(value = "hello-service",fallback = FeignFallBack.class) public interface FeignService { //服务中方法的映射路径 @RequestMapping("/hello") String hello(); @RequestMapping(value = "/hellol", method= RequestMethod.GET) String hello(@RequestParam("name") String name) ; @RequestMapping(value = "/hello2", method= RequestMethod.GET) User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age); @RequestMapping(value = "/hello3", method= RequestMethod.POST) String hello(@RequestBody User user); }
接着在Controller层注入FeiService这个接口,进行远程服务调用,代码以下:
/** * Created by cong on 2018/5/17. */ @RestController public class ConsumerController { @Autowired FeignService feignService; @RequestMapping("/consumer") public String helloConsumer(){ return feignService.hello(); } @RequestMapping("/consumer2") public String helloConsumer2(){ String r1 = feignService.hello("hjc"); String r2 = feignService.hello("hjc", 23).toString(); String r3 = feignService.hello(new User("hjc", 23)); return r1 + "-----" + r2 + "----" + r3; } }
接着在Feign模块的启动类哪里打上Eureka客户端的注解@EnableDiscoveryClient Feign客户端的注解@EnableFeignClients,代码以下:
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class FeignApplication { public static void main(String[] args) { SpringApplication.run(FeignApplication.class, args); } }
接着启动启动类,浏览器上输入localhost:8083/consumer 运行结果以下:
能够看到负载均衡轮询出现hello1,hello2。
接着继续在浏览器上输入localhost:8083/consumer2,运行结果以下:
接下来咱们进行Feign声明式调用服务下的,服务降级的使用,那么咱们就必须新建一个FeignFallBack类来继承FeiService,代码以下:
package hjc; import org.springframework.stereotype.Component; /** * Created by cong on 2018/5/17. */ @Component public class FeignFallBack implements FeignService{
//实现的方法是服务调用的降级方法 @Override public String hello() { return "error"; } @Override public String hello(String name) { return "error"; } @Override public User hello(String name, Integer age) { return new User(); } @Override public String hello(User user) { return "error"; } }
接着咱们再把那两个服务提供模块provider1,provider2模块进行中止,运行结果以下所示:
能够看到咱们这几个调用,都进行了服务降级了。
那么若是咱们想精确的控制一下Hystrix的参数也是能够的,比方说跟Hystrix结合的参数,那么能够在FeignClient注解里面配置一个Configuration=XXX类.class属性,在哪一个类里面精确的指定一下属性。
或者在application.yml里面配置,以下:
hystrix: command: default: execution: isolation: thread: timeoutinMilliseconds: 5000 ribbon: connectTimeout: 500 #若是想对单独的某个服务进行详细配置,以下 hello-service: ribbon: connectTimeout: 500
这里知足了咱们大部分场景的调用,可是有写精细场景,仍是要用原生的Hystrix,跟咱们以前的Hystrix用法一下,不要走Feign客户端调用就好了,以下:
/** * Created by cong on 2018/5/17. */ public class HjcCommand extends HystrixCommand { protected HjcCommand(HystrixCommandGroupKey group) { super(group); } @Override protected Object run() throws Exception { return null; } }
那么咱们若是想用原声的HystrixCommand去搞一个异步请求怎么办?代码以下:
首先再引入一个依赖,feign客户端没有默认引入进来,须要咱们本身引入:
<dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-javanica</artifactId> <version>1.5.9</version> </dependency>
接着用HystrixCommand注解方式实现:
/** * Created by cong on 2018/5/17. */ @Service public class HjcCommand { @Autowired private FeignService feignService; //同步方式 @HystrixCommand public Future<String> getEmployeesAsync(){ return new AsyncResult<String>() { @Override public String invoke() { return feignService.hello("hjc"); } }; } //用同步方式还不如直接用Feign客户端 @HystrixCommand public String getEmployeesAsync1(){ return feignService.hello("laowang"); } }
这样还不行,咱们还须要声明一个切面,HystrixConfiguration,接着,将HystrixConfiguration加入到spring管理,代码以下:
@Configuration public class HystrixConfiguration { @Bean public HystrixCommandAspect hystrixAspect(){ return new HystrixCommandAspect(); } }
转自https://www.cnblogs.com/huangjuncong/p/9053576.html