• SpringCloud实战5-Feign声明式服务调用


    SpringCloud实战5-Feign声明式服务调用

    在前面的文章中可以发现当我们通过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是用@FeignClient来映射服务的。

    首先第一步,在原来的基础上新建一个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;
        }
    }
    复制代码

    接下来用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();
        }
    
    }
  • 相关阅读:
    CSS学习(五)
    1. Git-2.12.0-64-bit .exe下载
    90.bower解决js的依赖管理
    89.[NodeJS] Express 模板传值对象app.locals、res.locals
    88.NODE.JS加密模块CRYPTO常用方法介绍
    87.node.js操作mongoDB数据库示例分享
    50.AngularJs directive详解及示例代码
    49.AngularJs 指令directive之controller,link,compile
    48.AngularJS ng-src 指令
    86.express里面的app.configure作用
  • 原文地址:https://www.cnblogs.com/handsome1013/p/10948243.html
Copyright © 2020-2023  润新知