zoukankan      html  css  js  c++  java
  • 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();
        }
    
    }
  • 相关阅读:
    jquery easy ui 学习 (8)basic treegrid
    jquery easy ui 学习 (7) TreeGrid Actions
    jquery easy ui 学习 (6) basic validatebox
    jquery easy ui 学习 (5) windowlayout
    jquery easy ui 学习 (4) window 打开之后 限制操纵后面元素属性
    提示“应用程序无法启动,因为应用程序的并行配置不正确”不能加载 System.Data.SQLite.dll
    visual studio 添加虚线的快捷键
    VS2010打开项目时,出现“已经在解决方案中打开了具有该名称的项目”问题的解决方案
    visual studio 编译时 出现 Files 的值 乱码
    微信 连接被意外关闭
  • 原文地址:https://www.cnblogs.com/handsome1013/p/10948243.html
Copyright © 2011-2022 走看看