1.Feign介绍
feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service。 SpringCloud集成了Ribbon和Eureka,同时可在使用Feign时提供负载均衡的http客户端。只需要创建一个接口, 然后添加注解即可!
feign,主要是社区,大家都习惯面向接口编程。这个是很多开发人员的规范。调用微服务访问两种方法
1.使用微服务名字 [ribbon+restTemplate]
2.使用接口和注解 [feign]
Feign能干什么?
- Feign旨在使编写Java Http客户端变得更容易,使用接口方式调用服务
- 前面在使用Ribbon + RestTemplate时, 利用RestTemplate对Http请求的封装处理,形成了一 套模板化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义,== 在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它(类似于以前Dao接口上标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可。) == 即可完成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon时,自动封装服务调用客户端的开发量。
- Feign集成了ribbon
2.使用Feign
(1)在之前项目的基础上再创建一个module,名为spring-cloud-consumer-dept-feign,与使用ribbon的spring-cloud-consumer-dept相区分,并将内容复制进去,注意依赖也要复制进去,添加feign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<!--不需要版本信息-->
</dependency>
(2)在spring-cloud-api模块添加包service,用于服务的接口调用,这个模块也要添加feign的依赖
(3)service添加接口
package edu.ncu.dong.service;
import edu.ncu.dong.pojo.Dept;
import org.springframework.cloud.openfeign.FeignClient;
import java.util.List;
/**
* 用于Feign的调用,@FeignClient注解参数含义
* name:指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现,也可以用value
* url: url一般用于调试,可以手动指定@FeignClient调用的地址
* decode404:当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException
* configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
* fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
* fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
* path: 定义当前FeignClient的统一前缀
*/
@FeignClient(value = "SPRING-CLOUD-PROVIDER-DEPT")//value内容是服务的名字
@Component
public interface DeptClientService {
//这里就是区别,这直接写对外暴露的接口,很像controller里写的东西,但是这是接口,并没有方法体
//这里的@RequestMapping的value要和服务提供者暴露的接口一致,我们要搞清楚,这个接口是要去服务提供者获取数据
@RequestMapping(value = "dept/list",method = RequestMethod.GET)
public List<Dept> queryAll();
@RequestMapping(value = "dept/get/{id}",method = RequestMethod.GET)
public Dept queryById(@PathVariable("id") int id);
@RequestMapping(value = "dept/add",method = RequestMethod.POST)
public boolean addOne(Dept dept);
}
(4)在spring-cloud-consumer-dept-feign项目下创建controller,去用接口调用这个DeptClientService:
@RestController
public class DeptConsumerController {
//这里使用RestTemplate模板类,调用另一个服务中暴露的接口
@Autowired
private RestTemplate restTemplate;
//因为需要调用的接口都在8001端口启动的服务下,所以我们定义了一个常量
//这是不使用ribbon时,写死了指定的url
//private static final String REST_URL_PREFIX="http://localhost:8001";
//现在使用ribbon进行负载均衡,我们通过服务名去获取
//private static final String REST_URL_PREFIX="http://SPRING-CLOUD-PROVIDER-DEPT";
//现在使用feign,接口方式调用,Autowired注入
@Autowired
private DeptClientService service;//service就通过feign,调用来自于api的模块
@RequestMapping(value = "consumer/dept/add",method = RequestMethod.POST)
public boolean addDept(@RequestBody Dept dept){
return service.addOne(dept);
}
@RequestMapping(value = "consumer/dept/get/{id}",method = RequestMethod.GET)
public Dept queryDeptById(@PathVariable("id") int id){
return service.queryById(id);
}
@RequestMapping(value = "consumer/dept/list",method = RequestMethod.GET)
public List<Dept> queryDeptList(){
return service.queryAll();
}
}
(5)在spring-cloud-consumer-dept-feign模块启动类添加注解@EnableFeignClients(basePackages = {“edu.ncu.dong”}),basePackages 表示需要扫描的包(这里的包指的是api模块下的包,而不是该模块下的包,因为结构是一样的,不要区分不清楚)
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"edu.ncu.dong"})
public class ConsumerDept_80_Feign {
public static void main(String[] args) {
SpringApplication.run(ConsumerDept_80_Feign.class,args);
}
}
(6)启动eureka服务(不必三个都启动,这样太卡了),启动3个服务提供者,启动consumer-dept-feign服务,测试是否能获取到:
获取成功,而且由于配置的负载均衡策略是随机,提供服务的也是随机的
由于feign是集成了ribbon的,所以既然可以更改为随机策略,那么就是可以自定义负载均衡策略的,这里不多说。