简介
Feign客户端是一个web声明式http(REST)远程调用工具,提供了接口和注解方式进行调用。springcloud为Feign 整合了Eureka,Ribbon,Hystrix 以提供服务发现、负债均衡还有服务保护能力,同时整合了SpringMVC注解。
(注意:从Spring Cloud Dalston开始,Feign默认是不开启Hystrix的。因此,如使用Dalston及以上版本请务必额外设置属性:feign.hystrix.enabled=true,否则断路器不会生效)
Feign原理
Feign设计思路
具体详情点击进入
环境搭建
示例代码
建立feign-client子工程,启动注册中心Eureka:7001,provider:8001和provider:8002提供方
Feign客户端
建立feign-consumer项目
1.添加依赖
为了更好的体现整合了Eureka,Ribbon,Hystrix,我将放入相关依赖包
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!--注册中心--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> </dependencies>
2.application.yml 配置文件
server: port: 9001 spring: application: name: feign-consumer#客户端注册进eureka服务列表内 eureka: client: service-url: defaultZone: http://eureka7001:7001/eureka //开启断路器 feign: hystrix: enabled: true
3.Feign客户端接口
在ProviderRemote类添加@FeignClient注解指定被调用者服务方以及fallback回调类,在服务熔断的时候返回fallback类中的内容。
package net.riking.springcloud.consumer.feign.remote; import net.riking.springcloud.consumer.feign.entity.User; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; @FeignClient(name = "provider", fallback = ProviderRemoteFallback.class) public interface ProviderRemote { @GetMapping("/user/provider") User provider(@RequestParam String username); @GetMapping("/user/provider/port") String port(); }
引申:
/* * Copyright 2013-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.cloud.openfeign; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; /** * Annotation for interfaces declaring that a REST client with that interface should be * created (e.g. for autowiring into another component). If ribbon is available it will be * used to load balance the backend requests, and the load balancer can be configured * using a <code>@RibbonClient</code> with the same name (i.e. value) as the feign client. * * @author Spencer Gibb * @author Venil Noronha */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FeignClient { /** * The name of the service with optional protocol prefix. Synonym for {@link #name() * name}. A name must be specified for all clients, whether or not a url is provided. * Can be specified as property key, eg: ${propertyKey}. */ @AliasFor("name") String value() default ""; /** * The service id with optional protocol prefix. Synonym for {@link #value() value}. * * @deprecated use {@link #name() name} instead */ @Deprecated String serviceId() default ""; /** * The service id with optional protocol prefix. Synonym for {@link #value() value}. */ @AliasFor("value") String name() default ""; /** * Sets the <code>@Qualifier</code> value for the feign client. */ String qualifier() default ""; /** * An absolute URL or resolvable hostname (the protocol is optional). */ String url() default ""; /** * Whether 404s should be decoded instead of throwing FeignExceptions */ boolean decode404() default false; /** * A custom <code>@Configuration</code> for the feign client. Can contain override * <code>@Bean</code> definition for the pieces that make up the client, for instance * {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}. * * @see FeignClientsConfiguration for the defaults */ Class<?>[] configuration() default {}; /** * Fallback class for the specified Feign client interface. The fallback class must * implement the interface annotated by this annotation and be a valid spring bean. */ Class<?> fallback() default void.class; /** * Define a fallback factory for the specified Feign client interface. The fallback * factory must produce instances of fallback classes that implement the interface * annotated by {@link FeignClient}. The fallback factory must be a valid spring * bean. * * @see feign.hystrix.FallbackFactory for details. */ Class<?> fallbackFactory() default void.class; /** * Path prefix to be used by all method-level mappings. Can be used with or without * <code>@RibbonClient</code>. */ String path() default ""; /** * Whether to mark the feign proxy as a primary bean. Defaults to true. */ boolean primary() default true; }
属性名 | 默认值 | 作用 | 备注 |
---|---|---|---|
value | 空字符串 | 调用服务名称,和name属性相同 | |
serviceId | 空字符串 | 服务id,作用和name属性相同 | 已过期 |
name | 空字符串 | 调用服务名称,和value属性相同 | |
url | 空字符串 | 一般用于调试,可以手动指定@FeignClient调用的地址 | |
decode404 | false | 配置响应状态码为404时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException | |
configuration | {} | 自定义当前feign client的一些配置 | 参考FeignClientsConfiguration |
fallback | void.class | 熔断机制,调用失败时,走的一些回退方法,可以用来抛出异常或给出默认返回数据。 | 底层依赖hystrix,启动类要加上@EnableHystrix |
path | 空字符串 | 自动给所有方法的requestMapping前加上前缀,类似与controller类上的requestMapping | |
fallbackFactory | void.class | 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码 | |
primary | true |
4.Feign自定义处理返回的回调值
创建ProviderRemoteFallback类继承与ProviderRemote实现回调的方法
package net.riking.springcloud.consumer.feign.remote; import net.riking.springcloud.consumer.feign.entity.User; import org.springframework.stereotype.Component; @Component public class ProviderRemoteFallback implements ProviderRemote{ @Override public User provider(String username) { User user =new User(); user.setDescription("系统繁忙,请稍候再试"); return user; } @Override public String port() { return "系统繁忙,请稍候再试"; } }
5.服务接口调用
package net.riking.springcloud.consumer.feign.controller; import net.riking.springcloud.consumer.feign.entity.User; import net.riking.springcloud.consumer.feign.remote.ProviderRemote; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user/consumer") public class UserConsumerController { @Autowired ProviderRemote providerRemote; @GetMapping public User consumer(@RequestParam String username) { User user = providerRemote.provider(username); user.setDescription("消费服务:"+user.getDescription()); return user; } @GetMapping("/port") public String port() { return "消费服务:"+providerRemote.port() ; } }
6.启动FeignConsumerApplication服务
package net.riking.springcloud.consumer.feign; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableDiscoveryClient @EnableFeignClients //开启Feign客户端 @EnableHystrix //开启熔断 public class FeignConsumerApplication { public static void main(String[] args) { SpringApplication.run(FeignConsumerApplication.class, args); } }
7.验证
负债均衡
启动工程后,连续访问:http://localhost:9001/user/consumer/port多次,可以看到如下页面:
断路器
关闭provider:8001和provider:8002提供方,访问:http://localhost:9001/user/consumer/port,可以看到如下面的页面:
这里只测试这一种,其他这里就不演示了