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