前面我们学习了eureka 服务的搭建,以及ribbon,hystrx,分布式开发中很重要的两个功能组件,负载均衡和服务熔断机制来对我们的微服务进行保护。
前面我们在进行eureka 服务进行调用时都是采用RestTemplate 进行封装http服务调用,形成了一套模板的调用方法,实际应用当中,某个我服务提供的服务接口会被我们在多处调用,这时候我们往往会自己封装服务的调用客户端。而springcloud 也为我们提供了这样的服务客户端封装组件-Fegin,
他提供了声明式服务的调用。
下面我们开始动手实践;
新建使用Feign 声明式服务调用的客户端,以后代码只贴出核心相关代码,否则会导致文章篇幅太长,文章被代码所充斥。
pom:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.3.RELEASE</version>
</dependency>
声明服务:
@FeignClient("HELLOSERVICE")public interface HelloService { @GetMapping("hello") String hello(@RequestParam String name);}
@FeignClient("HELLOSERVICE")这里 声明了 helloService 服务,注解中的参数名称就是eureka中注册的服务名称,注意这里服务名不区分大小写,建议直接从eureka服务注册中心拷贝。然后我们使用了springmvc 自带的注解@GetMapping进行需要调用的方法声明。
controller:
@RestControllerpublic class Controller { @Autowired private HelloService helloService; @GetMapping("feign-hello") private String test(@RequestParam String name){ return helloService.hello(name); }}
springboot 引导类:
@FeignClient("HELLOSERVICE")
public interface HelloService {
@GetMapping("hello")
String hello(@RequestParam String name);
}
@EnableFeignClients 开启feigin声明式服务。
下面我们启动服务,并在浏览器输入:http://localhost:8088/feign-hello?name=alibb
查看输出:
我们看到了服务器返回了预期的响应。
不过这里有个小坑点,这里做小说明,我们在进行url传值时,我们的服务提供者和Feign 声明的接口中都必须加@RequestParam注解,否则会爆出405错误。但是我们知道 springmvc 中url传值,不是必须制定@RequestParam注解的,框架自动能够匹配参数。笔者不知道是Feign 作者故意为之还是有其他的考量。
下面我们来介绍下Fegin 的继承特性,我们发现Feign 的客户端代码几乎可以直接从服务实现中复制过来,是否可以进一步进行抽象呢,springcloud Feign 针对此项问题进行了抽象。为了复用接口和 DTO ,我们新建一个helloApi 工程:
pom:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
请求接口定义:
@RequestMapping("refact")
public interface HelloServiceApi {
@RequestMapping("/hello1")
String hello1(@RequestParam String name);
@PostMapping("/hello2")
String hello2(@RequestBody User user);
}
DTO定义:
@Data
public class User {
private String name;
private Integer age;
}
我们看到这个就是一个请求api 的定义,没有任何特殊之处,下面我们进行服务提供者的修改:
首先引入api的pom依赖:
<dependency>
<groupId>com.ethan.springclod.api</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
新建一个Controller 并实现上述接口:
@RestController
@Slf4j
public class HelloFeignController implements HelloServiceApi {
@Override
public String hello1(String name) {
log.info("feign hello1:{}" ,name);
return "hello world " + name;
}
@Override
public String hello2(User user) {
log.info("feign hello2:{}" ,user);
return user.toString();
}
}
然后启动服务。
在服务调用端我们也作出调整,在pom中同样添加helloservice 的api 依赖,然后创建RefactHelloService:
@FeignClient("HELLOSERVICE")
public interface RefactHelloService extends HelloServiceApi {
}
controller 调整:
@Autowired
private RefactHelloService helloServiceApi;
@GetMapping("feign-hello")
private String test(@RequestParam String name){
return helloServiceApi.hello1(name);
}
@GetMapping("feign-hello3")
private String test3(){
User user = new User();
user.setName("ethan");
user.setAge(28);
return helloServiceApi.hello2(user);
}
然后我们启动服务发送请求测试:http://localhost:8088/feign-hello3
看到对应的返回和控制台输出,一切正常。
由此,我们可以通过对外封装api,给调用者调用,可以提高我们的开发效率。
本篇关于Feign 介绍到此结束,如有不对之处,欢迎指正!