SpringCloud学习之Feign

今天我们来聊聊Springcloud全家桶中的第三个组件Feign(声明式的web service客户端),那么他的作用是什么呢?他和Ribbon有什么区别呢?

目前,在Spring cloud 中服务之间通过restful方式调用有两种方式

  • restTemplate+Ribbon :通过服务名称远程调用服务
  • feign:通过接口和注解远程调用服务

1、Feign是什么?

Feign是一个声明式的web service客户端,它使得编写web service客户端更为容易。创建接口,为接口添加注解,即可使用Feign。Feign可以使用Feign注解或者JAX-RS注解。Spring Cloud为Feign添加了Spring MVC的注解支持,并整合了Ribbon和Eureka来为使用Feign时提供负载均衡。

feign让微服务之间的调用变得更简单了。

Spring Cloud Netflix 的微服务都是以 HTTP 接口的形式暴露的,所以可以用 Apache 的 HttpClient 或 Spring 的 RestTemplate 去調用(RestTemplate是对HTTP请求的封装处理)

而 Feign 是一個使用起來更加方便的 HTTP 客戶端,它用起來就好像調用本地方法一樣,完全感覺不到是調用的远程方法

总结起来就是:发布到注册中心的服务方接口,是 HTTP 的,也可以不用 Ribbon 或者 Feign,直接浏览器一样能够访问

只不过 Ribbon 或者 Feign 调用起来要方便一些,最重要的是:它俩都支持软负载均衡

Feign集成了Ribbon

注意:spring-cloud-starter-feign 里面已经包含了 spring-cloud-starter-ribbon(Feign 中也使用了 Ribbon)

从实践上看Feign只需要定义服务绑定接口且以声明式的注解方法,采用feign的方式更优雅(feign内部也使用了ribbon做负载均衡)。

2、Feign怎么使用?

  • 1、在我们之前的springcloud-api(给各个服务提供pojo)这个服务中引入feign依赖

<!--Feign-->

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-feign</artifactId>

<version>1.4.6.RELEASE</version>

</dependency>

  • 2、在springcloud-api中编写DeptClientService接口,方便其他服务属性注入调用

在该接口中配置@FeignClient(value = "springcloud-provider")注解,value值为服务名,可以被其他服务直接调用,通过客户端去找springcloud-provider服务名,进行负载均衡

package com.baoji.springcloud.service;

import com.baoji.springcloud.pojo.Dept;

import org.springframework.cloud.openfeign.FeignClient;

import org.springframework.stereotype.Component;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.PostMapping;

import java.util.List;

@Component //此注解是将此接口注入到spring中

@FeignClient(value = "springcloud-provider") //可以被其他服务直接调用,通过客户端去找springcloud-provider服务名,进行负载均衡

public interface DeptClientService {

@GetMapping("/dept/get/{id}")

public Dept quaryById(@PathVariable("id") Long id);

@GetMapping("/dept/list")

public List<Dept> queryAll();

@PostMapping("/dept/add")

public boolean addDept(Dept dept);

}

  • 3、创建一个springcloud-consume-feign-80服务消费者(feign方式)的服务(所有配置和springcloud-consume-80的配置基本类似,复制过来即可)

在该消费者服务中添加feign依赖

 <!--Feign-->

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-feign</artifactId>

<version>1.4.6.RELEASE</version>

</dependency>

将api服务业务接口直接属性注入到该服务中,方便控制层的调用

package com.baoji.springcloud.controller;

import com.baoji.springcloud.pojo.Dept;

import com.baoji.springcloud.service.DeptClientService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

import java.util.List;

@RestController

public class DeptConsumerController {

//自动属性注入service

@Resource

private DeptClientService service = null;

//消费者请求的地址

@RequestMapping("/consumer/dept/get/{id}")

public Dept get(@PathVariable("id") Long id) {

//服务器返回对应的对象

return service.quaryById(id);

}

@RequestMapping("/consumer/dept/add")

public boolean add(Dept dept) {

//返回post类型的对象,三个参数(请求的地址,拼接的参数,返回响应的字节码)

return service.addDept(dept);

}

@RequestMapping("/consumer/dept/list")

public List<Dept> list(){

//返回get类型的对象,两个参数(url,返回响应的字节码)

return service.queryAll();

}

}

编写启动类

此类多了个@EnableFeignClients(basePackages = {"com.baoji.springcloud"}) 注解,去扫描哪些需要调用业务服务接口的注解包

package com.baoji.springcloud;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

import org.springframework.cloud.openfeign.EnableFeignClients;

// Ribbon和Eureka整合之后, 客户端可以直接调用,不用关心IP和端口号

@SpringBootApplication

@EnableEurekaClient //eureka客户端注解 使用的是eureka发现功能

//Feign集成了Ribbon,通过Ribbon实现了负载均衡,通过Feign实现了远程调用

@EnableFeignClients(basePackages = {"com.baoji.springcloud"}) //去扫描哪些需要调用业务接口注解包

public class FeignConsume_80 {

public static void main(String[] args) {

SpringApplication.run(FeignConsume_80.class,args);

}

}

3、Feign和Ribbon调用服务在具体实现上的不同?

  • 1、我们来看看Ribbon实现服务调用的controller层

Ribbon实现原理:

Riggon是使用Spring中提供的RestTemplate对象来实现远程调用,RestTemplate对象对Http请求进行了封装处理,给消费者服务通过RestTemplate对象访问生产者服务提供了一套模板,它是根据服务名来调用生产者,根据restTemplat对象调用底层获取服务提供者的一系列方法来实现服务调用

package com.baoji.springcloud.controller;

import com.baoji.springcloud.pojo.Dept;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController

public class DeptConsumerController {

//消费者:不应该有service层

//RestTemplate 供我们直接调用就可以 直接手动注册到spring中

//参数(url,请求路径:Map,Class<T> responseType)

@Autowired

private RestTemplate restTemplate; //提供多种快捷访问Http服务的方法,简单的restFul服务模板

//请求路径前固定的url

// private static final String REST_URL_PREFIX = "http://localhost:8080";

//用ribbon实现负载均衡时,我们消费者访问的地址就是一个变量,通过服务名来访问,

// 这个服务名存在Eureka的多个注册中心里,通过Ribbon负载均衡机制获取它到底调用哪个生产者

private static final String REST_URL_PREFIX = "http://springcloud-provider";

//消费者请求的地址

@RequestMapping("/consumer/dept/get/{id}")

public Dept get(@PathVariable("id") Long id) {

//服务器返回对应的对象

return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);

}

@RequestMapping("/consumer/dept/add")

public boolean add(Dept dept) {

//返回post类型的对象,三个参数(请求的地址,拼接的参数,返回响应的字节码)

return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);

}

@RequestMapping("/consumer/dept/list")

public List<Dept> list(){

//返回get类型的对象,两个参数(url,返回响应的字节码)

return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);

}

}

  • 2、接下来我们来看Reign方式服务调用的controller层

Feign实现原理:

简单来说,Feign的实现比较简单,它集成了Rebbon,它只要编写一个接口和使用注解即可,它是将所有的业务内容写在一个接口中,服务消费者通过属性注入该接口,去调用该接口中的方法即可完成远程服务间的调用,这样就感觉到远程服务间的调用和之前的本地Controller层调用service层的实现一样简单

service接口:

package com.baoji.springcloud.service;

import com.baoji.springcloud.pojo.Dept;

import org.springframework.cloud.openfeign.FeignClient;

import org.springframework.stereotype.Component;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.PostMapping;

import java.util.List;

@Component //此注解是将此接口注入到spring中

@FeignClient(value = "springcloud-provider") //可以被其他服务直接调用,通过客户端去找springcloud-provider服务名,进行负载均衡

public interface DeptClientService {

@GetMapping("/dept/get/{id}")

public Dept quaryById(@PathVariable("id") Long id);

@GetMapping("/dept/list")

public List<Dept> queryAll();

@PostMapping("/dept/add")

public boolean addDept(Dept dept);

}

消费者controller类

就是单纯的属性注入service,服务消费者调用service里面的方法即可。

package com.baoji.springcloud.controller;

import com.baoji.springcloud.pojo.Dept;

import com.baoji.springcloud.service.DeptClientService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

import java.util.List;

@RestController

public class DeptConsumerController {

//自动属性注入service

@Resource

private DeptClientService service = null;

//消费者请求的地址

@RequestMapping("/consumer/dept/get/{id}")

public Dept get(@PathVariable("id") Long id) {

//服务器返回对应的对象

return service.quaryById(id);

}

@RequestMapping("/consumer/dept/add")

public boolean add(Dept dept) {

//返回post类型的对象,三个参数(请求的地址,拼接的参数,返回响应的字节码)

return service.addDept(dept);

}

@RequestMapping("/consumer/dept/list")

public List<Dept> list(){

//返回get类型的对象,两个参数(url,返回响应的字节码)

return service.queryAll();

}

}

启动类:

启动类中加入@EnableFeignClients(basePackages = {"com.baoji.springcloud"})注解,告诉服务消费者去扫描哪些需要调用业务接口注解包即可

package com.baoji.springcloud;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

import org.springframework.cloud.openfeign.EnableFeignClients;

// Ribbon和Eureka整合之后, 客户端可以直接调用,不用关心IP和端口号

@SpringBootApplication

@EnableEurekaClient //eureka客户端注解 使用的是eureka发现功能

//Feign集成了Ribbon,通过Ribbon实现了负载均衡,通过Feign实现了远程调用

@EnableFeignClients(basePackages = {"com.baoji.springcloud"}) //去扫描哪些需要调用业务接口注解包

public class FeignConsume_80 {

public static void main(String[] args) {

SpringApplication.run(FeignConsume_80.class,args);

}

}


总体来说:Feign内部集成了Rebbon,使用简单,只需要将业务写在接口中,服务消费者调用该接口即可,将远程间的服务调用类似的简化成了本地的mvc架构方式调用,控制层调用业务层,但是总的来说,微服务是使用Ribbon实现负载均衡,feign实现远程间的服务调用,feign的使用,更好的体现了java面向接口编程,是面向接口的远程调用,ribbon+restTemplate是一种面向服务的远程调用,两者方式不同,使用时采取自愿,都会用最好!!!



好了,今天Feign组件的学习就到这了,今天你将get到Feign的基本概念、怎么使用Feign、Fiegn和Ribbon进行远程调用服务的区别,接下来你将学习到微服务中Hystrix服务熔断与降级的内容,当服务炸掉之后,微服务是怎么保证安全的呢?期待下一篇博客吧!记得点赞👍+关注哦!!!


以上是 SpringCloud学习之Feign 的全部内容, 来源链接: utcz.com/a/25449.html

回到顶部