声明式服务调用SpringCloud Feign
springcloud有两种接口调用方式,一种是通过RestTemplate,像下面这样调用:
restTemplate.getForObject("http://app-member/getmember", String.class);
个人理解,这种方式将接口的调用与业务代码掺杂在一起,不太友好,基本不用。
另一种是Feign客户端调用,Fegin采用接口加注解的方式实现,易读性较强。
1.Feign简介
Feign客户端是一个web声明式http远程调用工具,提供了接口和注解方式进行调用。
2. Feign的使用
创建一个父工程,然后再分别创建三个Module:Eureka Server ,memberService 和 orderService,并关闭eureka自我保护
2.1父工程搭建
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lchtest</groupId>
<artifactId>springcloud2.0-eureka-selfprotect</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>eureka-server</module>
<module>springcloud2.0-eureka-selfprotect-eurekaserver</module>
<module>springcloud2.0-eureka-selfprotect-order</module>
<module>springcloud2.0-eureka-selfprotect-member</module>
</modules>
</project>
2.2 EurekaServer模块搭建
- pom引入spring-cloud-starter-netflix-eureka-server 依赖:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.lchtest</groupId>
<artifactId>springcloud2.0-eureka-selfprotect</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>springcloud2.0-eureka-selfprotect-eurekaserver</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
- yaml配置,关闭Eureka自我保护
server:
port: 8100
eureka:
instance:
#注册中心ip地址
hostname: 127.0.0.1
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
# 不将自己注册到注册中心
register-with-eureka: false
fetch-registry: false
server:
# 关闭自我保护机制,保证服务不可用时及时剔出
enable-self-preservation: false
# 踢出失效服务的间隔
eviction-interval-timer-in-ms: 2000
- 启动类 @EnableEureakServer开启注册中心
package com.lchtest.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
//@EnableEureakServer表示开启注册中心
@EnableEurekaServer
public class AppEurekaServer {
public static void main(String[] args) {
SpringApplication.run(AppEurekaServer.class, args);
}
}
2.3 MemberService搭建
- pom
引入spring-cloud-starter-netflix-eureka-client 依赖和springboot-web组件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.lchtest</groupId>
<artifactId>springcloud2.0-eureka-selfprotect</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>springcloud2.0-eureka-selfprotect-member</artifactId>
<dependencies>
<!-- eurekaclient 把menu服务在注册中心注册,使他自己成为一个服务提供者-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
- yaml
配置注册中心地址并设置客户端心跳检测时间
# 会员服务项目端口号
server:
port: 8070
# 服务别名--服务注册到注册中心的名称
spring:
application:
name: app-member
eureka:
client:
service-url:
#将当前服务注册到eureka注册中心
defaultZone: http://localhost:8100/eureka/
# 将自己注册到注册中心,设置为true
register-with-eureka: true
# 检索服务信息
fetch-registry: true
# eureka客户端与eureka服务端心跳检测及续约时间,本地开发时设置小些,保证服务不可用时就踢出
instance:
# eureka客户端向服务端发送心跳的时间间隔,单位为秒
lease-renewal-interval-in-seconds: 1
# eureka服务端在收到最后一次心跳检测之后等待的事件上限,单位为秒,超过此时间则剔除
lease-expiration-duration-in-seconds: 2
- 启动类:
使用@EnableEurekaClient注解将member服务注册到注册中心
package com.lchtest.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class AppMember {
public static void main(String[] args) {
SpringApplication.run(AppMember.class, args);
}
}
- MemberController
package com.lchtest.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MemberController {
@Value("${server.port}")
private String port;
@RequestMapping("/member/getmember")
public String getMemberByFeign() {
return "member service port=" + port;
}
}
2.4 OrderService搭建
- pom依赖
集成Feign客户端spring-cloud-starter-openfeign 和springboot-web组件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.lchtest</groupId>
<artifactId>springcloud2.0-eureka-selfprotect</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>springcloud2.0-eureka-selfprotect-order</artifactId>
<dependencies>
<!-- eurekaclient 把menu服务在注册中心注册,使他自己成为一个服务提供者-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 集成feign客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>
- 配置文件
# 会员服务项目端口号
server:
port: 8001
# 服务别名--服务注册到注册中心的名称
spring:
application:
name: app-order
eureka:
client:
service-url:
#将当前服务注册到eureka注册中心
defaultZone: http://localhost:8100/eureka/
# 将自己注册到注册中心,设置为true
register-with-eureka: true
# 检索服务信息
fetch-registry: true
# eureka客户端与eureka服务端心跳检测及续约时间,本地开发时设置小些,保证服务不可用时就踢出
instance:
# eureka客户端向服务端发送心跳的时间间隔,单位为秒
lease-renewal-interval-in-seconds: 1
# eureka服务端在收到最后一次心跳检测之后等待的事件上限,单位为秒,超过此时间则剔除
lease-expiration-duration-in-seconds: 2
- Feign客户端接口定义
package com.lchtest.springcloud.feignclient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 声明式Feign客户端调用服务
* @author pc
*/
@FeignClient(value = "app-member")
public interface MemberFeign {
@RequestMapping("/member/getmember")
public String getmember();
}
@FeignClient(value = “app-member”) ,@FeignClient代表一个Feign客户端,value的值是该客户端要调用的服务在注册中心里的名称
@RequestMapping("/member/getmember") 就是rpc方式要调用的远程接口/member/getmember,是服务提供者对外暴露的接口
猜测FeignClient注解本质上应该是通过反射获取到注解的值,拿到要调用的服务的名称,然后去注册中心获取到服务对应的地址信息,然后再根据@RequestMapping注解
的值组装接口调用地址,最后以HttpClient方式去调用
- Controlelr
controller中注入Feign客户端接口的实例MemberFeign,调用对应方法即可
package com.lchtest.springcloud.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.lchtest.springcloud.feignclient.MemberFeign;
@RestController
@RequestMapping("/orderfeign")
public class FeignClientTestController {
@Autowired
private MemberFeign memberFeign;
/**
* 通过feign客户端调用member服务:http://localhost:8001/orderfeign/getmemberByFeign
* @return
*/
@RequestMapping("/getmemberByFeign")
public String getmember() {
return "通过Feign客户端调用member服务,响应是:" + memberFeign.getmember();
}
}
- 主启动类 需要加上@EnableFeignClients注解启用feign客户端
package com.lchtest.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients // 启用feign客户端
public class AppOrder {
public static void main(String[] args) {
SpringApplication.run(AppOrder.class, args);
}
}
Feign客户端使用步骤总结
- 使用Feign客户端的项目集成Feign客户端
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- Feign客户端接口定义
接口类名上面加上注解@FeignClient(value = “app-member”) 来声明Feign客户端,并指定要调用的微服务在注册中心注册的名称,@RequestMapping指定要调用的接口方法:
@FeignClient(value = "app-member")
public interface MemberFeign {
@RequestMapping("/member/getmember")
public String getmember();
}
- 使用Feign客户端的地方注入Feign客户端接口并调用
// 注入
@Autowired
private MemberFeign memberFeign;
// 接口调用
memberFeign.getmember();
- 启动类加上@EnableFeignClients 注解启用Feign客户端
当前Feign客户端调用缺点![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/cd987d3036c33f37228c393b7bd6f883.png)
可以看到,order服务要通过Feign客户端调用member服务的/member/getmember接口,就必须在order服务中定义一个相同的Feign客户端接口,如果有很多个接口,这样的重复代码就很多了,因此这样的项目结构不是很合理。
点击下载代码
参见springcloud2.0-eureka-selfprotect 工程