SpringCloud版本:2021.0.1 SpringBoot版本:2.6.3
系列文章
SpringCloud学习(一)----- Eureka搭建
SpringCloud学习(二)----- SpringBoot Admin搭建(与Eureka整合)
SpringCloud学习(三)----- Gatewayw网关搭建
SpringCloud学习(四)----- Gatewayw网关完善(限流)
SpringCloud学习(五)----- Gatewayw网关完善(Resilience4j断路器)
SpringCloud学习(六)----- Gatewayw网关完善(防止SQL注入)
SpringCloud学习(七)----- 使用Feign调用别的微服务的方法
SpringCloud学习(八)----- Gateway网关及其他微服务接入Swagger接口文档
参考文章:
今日教学:RestTemplate 结合 Ribbon 使用
FEIGN调用出现权限问题 FEIGN.FEIGNEXCEPTION$UNAUTHORIZED: [401] DURING [GET] TO[....]
因为在微服务的框架中,已经把所有的服务的功能区分的很细了,所以有可能会出现一种问题,就是比如某个微服务需要用到某个功能,但这个功能已经划分在别的服务并已经开发完成了,那么这个时候就可以用到Feign这个来调用别的服务的方法了。
一、微服务之间一般用什么方法来进行互相的方法调用 ?
一般常用的有两种方法,即Ribbon + RestTemplate进行微服务调用或者使用Feign进行微服务调用。当然,也有一个最原始的方法,那就是http接口,这个也可以实现微服务之间的方法的调用的功能,但就是比较麻烦,头铁的可以试试。那么,Ribbon + RestTemplate和Feign这两种方法有什么区别吗?那当然是有的,但也没有那么大的区别。
1、它们的启动类注解不同,Ribbon是@RibbonClient,Feign的是@EnableFeignClients。
2、服务指定的位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明。
3、调用方式不同,Ribbon需要自己构建http请求,先模拟http请求然后再使用RestTemplate发送给其他服务,步骤比较繁琐。但Feign只需要将调用的方法定义成抽象方法即可,当然,前提是得已经把服务注册到注册中心。
那么,它们之间对比下来,那个更好呢?
1、Ribbon弊端:代码里会充斥着大量的url,在小型项目中还好,但在大型项目里,维护成本就会很高了。
2、Feign弊端:如果微服务调用的方法入参发生了变化,那么对应的Feign方法也得进行相应的更改,但这个我觉得还是可以接受的。
不过呢,一般开发人员都会选用Feign来进行微服务之间的调用,因为如果真的使用Ribbon + RestTemplate的话,那么维护成本就太高了,相比较下,Feign还是比较好的。
那么,回归主题,首先简单介绍一下Ribbon + RestTemplate的使用。
1、Ribbon + RestTemplate
首先,是Ribbon的pom依赖导入,不过如果用的是Eurker作为注册中心的话,也不用导入,因为Eureka 中已经引用了Ribbon。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
然后我们需要在启动类里面的方法创建一个负载均衡的RestTemplate Bean
@SpringBootApplication
@EnableDiscoveryClient
public class TestApplicaton {
//创建一个负载均衡的RestTemplate Bean
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(TestApplicaton.class, args);
}
}
再然后,在要使用的方法里进行引入就可以了。
@Autowired
private RestTemplate restTemp;
public String test(){
//与Eurka集成,将服务注册到Eurka,url中使用注册到Eurka中服务名来进行调用
ResponseEntity<String> rest = restTemp.getForEntity("http://test-service/test/hello" , String.class);
if (rest != null){
return rest.getBody();
}
return null;
}
2、Feign
(1)引入pom依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
(2)在启动类上加上 @EnableFeignClients注解
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class TestApplicaton {
public static void main(String[] args) {
SpringApplication.run(TestApplicaton.class, args);
}
}
(3)新建访问其他微服务的接口
@FeignClient("test-service")
public interface ServiceApi {
@PostMapping("/test/hello")
String hello();
}
- @FeignClient("test-service")中的“test-service”是spring:application:name,即注册中心中配的应用名,即注册到注册中心里的服务名
- @PostMapping("/test/hello") 是要调用的微服务的url
在使用Feign中,我还出现过401的问题,这种情况为没有认证就请求了资源服务器的资源,解决办法为使用Feign的时候把请求的认证信息传递过去,或者资源服务那边开放一些接口。不过开放接口的话情况有点多,所以就选择把token携带过去了。feign提供了一个名为RequestInterceptor得拦截器,可以在请求的时候指定请求头。
解决方法就是加一个配置文件, 在请求的时候指定请求头,就可以了。
@Configuration
public class FeignConfig implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
requestTemplate.header("Authorization", request.getHeader("Authorization"));
}
}