在前面的文章中可以发现当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻。

那么有没有更好的解决方案呢?答案是确定的有,Netflix已经为我们提供了一个框架:Feign。

Feign是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单。Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息。

而Feign则会完全代理HTTP请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。Feign整合了Ribbon和Hystrix(关于Hystrix我们后面再讲),可以让我们不再需要显式地使用这两个组件。

总起来说,Feign具有如下特性:

  • 可插拔的注解支持,包括Feign注解和JAX-RS注解;
  • 支持可插拔的HTTP编码器和解码器;
  • 支持Hystrix和它的Fallback;
  • 支持Ribbon的负载均衡;
  • 支持HTTP请求和响应的压缩。

这看起来有点像我们springmvc模式的Controller层的RequestMapping映射。这种模式是我们非常喜欢的。Feign是[email protected]

首先第一步,在原来的基础上新建一个Feign模块,接着引入相关依赖,引入Feign依赖,会自动引入Hystrix依赖的,如下:

    <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; 
    } 
}

[email protected](“服务名称”)映射服务调用。代码如下:

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客户端的注[email protected]  [email protected],代码如下:

@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


发布评论

分享到:

IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

Hystrix 配置参数全解析知识解答
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。