其他分享
首页 > 其他分享> > SpringCloud07:Fegin负载均衡(基于服务端)

SpringCloud07:Fegin负载均衡(基于服务端)

作者:互联网

1、Feign简介

Feign是声明式Web Service客户端,它让微服务之间的调用变得更简单,类似controller调用service。SpringCloud集成了Ribbon和Eureka,可以使用Feigin提供负载均衡的http客户端

只需要创建一个接口,然后添加注解即可~

Feign,主要是社区版,大家都习惯面向接口编程。这个是很多开发人员的规范。调用微服务访问两种方法

  1. 微服务名字 【ribbon】
  2. 接口和注解 【feign】

Feign能干什么?

Feign默认集成了Ribbon

2、Feign的使用步骤

2.1 依据springcloud-consumer-ribbon-80模块复制,创建springcloud-consumer-feign-80模块,修改依赖

<dependencies>
    <dependency>
        <groupId>com.godfrey</groupId>
        <artifactId>springcloud-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--Feign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <!--Eureka: Ribbon需要从Eureka服务中心获取要拿什么-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>com.godfrey</groupId>
        <artifactId>springcloud-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

Feign实现消费者模块调用服务提供者模块的原理和原来的Dubbo+Zookeeper类似,即需要使用注解实现远程注入,所以我们直接在springcould-api模块先添加Feign依赖:

<!--Feign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2.2 在service包下新建一个接口DeptClientService,

这个接口中的方法定义自己随意,只是方法上面要像controller一样写上@RequestMapping或者它的变体@GetMapping、@PostMapping等,但是这个接口上面不需要使用注解@Controller或@RestController

这个接口上面需要使用注解@FeignClient(value = “服务集群在注册中心中的名称”)和注解@Component或者它的变体@Service;其中注解@FeignClient+value属性用于指定注册中心中哪一个服务中的

@Component
@FeignClient(value = "SPRINGCOULD-PROVIDER-DEPT")
public interface DeptClientService {

    @PostMapping("/dept/add")
    boolean addDept(Dept dept);
    
    @GetMapping("/dept/queryById/{id}")
    Dept queryById(@PathVariable("id") Long id);

    @GetMapping("/dept/queryList")
    List<Dept> queryAll();
}

注意:还需要在这个接口上加上注解@Component/@Service,否则这个接口不会被spring托管/装配到spring容器中,那么我们在消费者model中使用这个类的时候就不能使用注解@Autowired实现对象自动注入到消费者的controller中(注意:我们是在springcould-api模块中定义的这个接口,并在这个接口上面加上了注解@Component,这个注解不是要在springcould-api模块中起作用,而是要在使用springcould-api模块的其他模块中起作用,即哪个模块导入了springcould-api模块,那么在这个model启动的时候,有注解@Component的这个接口就会被装配到spring容器中去,然后我们只需要在当前的这个模块中使用注解@Autowired就可以获取到这个接口在spring容器中的实例,就可以调用它内部的方法实现对应的功能)

通过Ribbon实现:—原来的controller:DeptConsumerController.java

@RestController
public class DeptConsumerController {

    private RestTemplate restTemplate;

    //Ribbon:我们这里的地址,应该是一个变量,通过服务名来访问
    //private static final String REST_URL_PREFIX = "http://localhost:8001";
    private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

    @Autowired
    DeptConsumerController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @PostMapping("/consumer/dept/add")
    public boolean addDept(Dept dept) {
        return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add/", dept, Boolean.class);
    }

    @RequestMapping("/consumer/dept/get/{id}")
    public Dept queryById(@PathVariable("id") Long id) {
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
    }

    @RequestMapping("/consumer/dept/list")
    public List<Dept> queryAll() {
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
    }
}

使用ribbon的时候,我们是直接将服务集群在注册中心中的服务名直接写死在代码中(private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";),通过拼接实现的消费者调用服务提供者对应的服务,拼接的后半段是服务对应功能在controller中暴露的API(/dept/add/,/dept/get/,/dept/get/)

通过Feign实现:—改造后controller:DeptConsumerController.java

@RestController
public class DeptConsumerController {

    private DeptClientService service;

    @Autowired
    public DeptConsumerController(@Qualifier("SPRINGCOULD-PROVIDER-DEPT") DeptClientService service) {
        this.service = service;
    }

    @PostMapping("/consumer/dept/add")
    public boolean addDept(Dept dept) {
        return service.addDept(dept);
    }

    @GetMapping("/consume/dept/queryById/{id}")
    public Dept queryById(@PathVariable("id") Long id) {
        return service.queryById(id);
    }

    @RequestMapping("/consumer/dept/queryAll")
    public List<Dept> queryAll() {
        return service.queryAll();
    }
}

使用Feign的时候,我们只需要在消费者的controller中组合进刚刚在springcloud-api中编写的接口方法即可,并使用注解@Autowired实现依赖注入,下面的方法就可以调用接口中的方法了,使用Feign之后,消费者的controller中方法的实现更加符合controller调service层提供服务的情形,并目整个代码结构更加的清晰了,就像真的就是在调用消费者模块中的service提供的服务—样,但是我们要是到,消费者模块根本就没有service层的代码

最后还要在spring boot项目的入口程序处加上启动Feign的注解@EnableFeignClients(basePackages = “我们定义的service所在的包路径”),注意:这里不是实际存在于springcould-consumer-dept-feign的model下的包路径,而是我们导入的springcould-api的包路径

2.3 启动Feign模块测试效果

从上面的测试结果可以发现,Feign默认使用的也是轮询算法

3、小结

所以Feign的核心就是将服务者提供的服务API进行本地化,存入消费者model中,然后再通过注解@EnableFeignClients和注解@FeignClient实现通过调用消费者模块中的本地化的服务API,调用到注册中心中真正服务提供者的API的作用(所以接口上的API映射需要和服务提供者的API保持一致),只需要4步就实现了Feign实现负载均衡

4、Feign和Ribbon如何选择?

根据个人习惯而定,如果喜欢REST风格使用Ribbon;如果喜欢社区版的面向接口风格使用Feign.

Feign 本质上也是实现了 Ribbon,只不过后者是在调用方式上,为了满足一些开发者习惯的接口调用习惯!

下面我们关闭springcloud-consumer-dept-80 这个服务消费方,换用springcloud-consumer-dept-feign(端口还是80) 来代替:(依然可以正常访问,就是调用方式相比于Ribbon变化了)

标签:Feign,调用,service,Fegin,接口,dept,SpringCloud07,注解,服务端
来源: https://www.cnblogs.com/MessiXiaoMo3334/p/14060521.html