SpringCloudAlibaba之OpenFeign

作者: adm 分类: java 发布时间: 2024-01-29

介绍
  在上面一篇介绍Nacos的文章最后,两个服务的相互调用是用的RestTemplate类完成的。但这种方式不是很推荐,更佳的方式是用OpenFeign组件去调用。OpenFeign是官方推出的服务调用和负载均衡组件,基于Ribbon和Hystrix,前身是第一代Spring Cloud的Feign,对Feign进行了扩展,支持了SpringMvc的相关注解。

常用注解
  OpenFeign是使用接口+注解实现的,因此了解它的常用注解是必要的,有以下几个:
@EnableFeignClients:在启动类上添加,用于开启OpenFeign功能。当项目启动时,会扫描带有@FeignClient的接口,生成代理类并注册到Spring容器中
@FeignClient:通知OpenFeign组件对该注解下的接口进行解析,通过动态代理的方式产生实现类,完成服务调用
@RequestMapping:SpringMvc中的注解,不过此时该注解表示发起Request请求(默认Get方式)
@GetMapping:SpringMvc中的注解,不过此时该注解表示发起Get请求
@PostMapping:SpringMvc中的注解,不过此时该注解表示发起Post请求

代码实现
  首先得把Nacos启动

  服务提供方,

  bootstrap.yml:

server:
  port: 8083
  servlet:
    context-path: /nacosProvider

spring:
  application:
    name: nacos-provider
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

  引入依赖:


    
        com.alibaba.cloud
        spring-cloud-starter-alibaba-nacos-discovery
        
        2.2.0.RELEASE
    
    
        org.projectlombok
        lombok
    

  服务方法:

@Controller
@RequestMapping("/provide")
public class ProviderController {

    @RequestMapping("/distribute")
    @ResponseBody
    public String distribute() {
        return "吃鸡胸肉";
    }

    @RequestMapping("/distribute1")
    @ResponseBody
    public String distribute1(String name, Integer age) {
        return "姓名:" + name + ",年龄:" + age;
    }

    @PostMapping("/distribute2")
    @ResponseBody
    public String distribute2(@RequestBody Person p) {
        return "身高:" + p.getHeight() + ",肤色:" + p.getSkin();
    }

}


import lombok.Data;

@Data
public class Person {

    private Integer height;

    private String skin;

}

  服务调用方,

  bootstrap.yml

server:
  port: 8082
  servlet:
    context-path: /nacosInvoke

spring:
  application:
    name: nacos-invoke
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

  引入依赖:


    
        com.alibaba.cloud
        spring-cloud-starter-alibaba-nacos-discovery
        
        2.2.0.RELEASE
    

    
        org.springframework.cloud
        spring-cloud-starter-openfeign
        2.2.0.RELEASE
    
    
        org.projectlombok
        lombok
    


  启动类上添加注解:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

//开启OpenFeign
@EnableFeignClients
@SpringBootApplication
public class NacosInvokeApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacosConfigApplication.class, args);
    }

}

  创建@FeignClient修饰的接口:

import com.gs.nacos_invoke.dto.Person;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * value值是服务提供方的服务名称
 */
@FeignClient(value = "nacos-provider")
public interface InvokeClient {

    @GetMapping("/nacosProvider/provide/distribute")
    String distribute();

    @GetMapping("/nacosProvider/provide/distribute1")
    String distribute1(@RequestParam("name") String name, 
    @RequestParam("age") Integer age);

    @PostMapping("/nacosProvider/provide/distribute2")
    String distribute2(@RequestBody Person p);

}

  Person类(服务调用方再创建一个,不是同一个):

import lombok.Data;

@Data
public class Person {

    private Integer height;

    private String skin;

}

  编写控制器,使用接口请求提供方的服务:

import com.gs.nacos_invoke.dto.Person;
import com.gs.nacos_config.feign.InvokeClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private InvokeClient invokeClient;


    @GetMapping("/invoke")
    public void invoke(String name, Integer age) {
        String str = invokeClient.distribute();
        System.out.println(str);
    }

    @GetMapping("/invoke1")
    public void invoke1() {
        String str = invokeClient.distribute1("coder", 20);
        System.out.println(str);
    }

    @GetMapping("/invoke2")
    public void invoke2() {
        Person p = new Person();
        p.setHeight(183);
        p.setSkin("黄皮肤");
        String s = invokeClient.distribute2(p);
        System.out.println(s);
    }

}

注意事项
  OpenFeign是基于Ribbon的,所以它默认是负载均衡的。其次,它也是基于Hystrix的,有超时降级的处理:默认服务提供方的接口超时时间是1s,超过1s服务调用方会报错。1s是可以配置的,按照业务需要调整。@FeignClient注解有个fallback属性,当该属性有值时,服务提供方超时,会返回程序所指定的降级值。

  服务调用方,bootstrap.yml添加(更规范的做法是引入spring-cloud-starter-alibaba-nacos-config依赖,nacos中新建配置,然后在这个配置中添加):

feign:
  hystrix:
    enabled: true
    
ribbon:
    # 请求连接的超时时间
    ConnectionTimeout: 3000
    # 请求处理的超时时间
    ReadTimeout: 3000

hystrix:
    command:
        default:
            execution:
                isolation:
                    thread:
                        timeoutInMilliseconds: 3000

  接口修改为:

import com.gs.nacos_invoke.dto.Person;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(value = "nacos-provider",
        fallback = InvokeClientFallback.class)
public interface InvokeClient {

    @GetMapping("/nacosProvider/provide/distribute")
    String distribute();

    @GetMapping("/nacosProvider/provide/distribute1")
    String distribute1(@RequestParam("name") String name, 
    @RequestParam("age") Integer age);

    @PostMapping("/nacosProvider/provide/distribute2")
    String distribute2(@RequestBody Person p);

}

  fallback指定的类:

import com.gs.nacos_invoke.dto.Person;
import org.springframework.stereotype.Component;

@Component
public class InvokeClientFallback implements InvokeClient {

    @Override
    public String distribute() {
        return "超时3s";
    }

    @Override
    public String distribute1(String name, Integer age) {
        return "超时3s";
    }

    @Override
    public String distribute2(Person p) {
        return "超时3s";
    }

}

  服务提供方ProviderController类的方法中,加入Thread.sleep(4000);或者throw new RuntimeException(“抛异常”);来触发降级(抛出未捕获的异常也能触发)。

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!