Ribbon、Feign和OpenFeign的区别
Ribbon
Ribbon 是 Netflix开源的基于HTTP和TCP等协议负载均衡组件
Ribbon 可以用来做客户端负载均衡,调用注册中心的服务
Ribbon的使用需要代码里手动调用目标服务,请参考官方示例:https://github.com/Netflix/ribbon
Feign
Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端
Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。
Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务
Feign支持的注解和用法请参考官方文档:https://github.com/OpenFeign/feign
Feign本身不支持Spring MVC的注解,它有一套自己的注解
OpenFeign
OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如@RequesMapping等等。
OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,
并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
springcloud F 及F版本以上 springboot 2.0 以上基本上使用openfeign,openfeign 如果从框架结构上看就是2019年feign停更后出现版本,也可以说大多数新项目都用openfeign ,2018年以前的项目在使用feign,可以这样粗率的分
接入OpenFeign(创建一个feign服务供消费)
需要新建一个服务来验证,项目结构如下
pom.xml
parent层pom依赖注入
<?xml version="1.0" encoding="UTF-8"?>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.yyzh.user</groupId>
<artifactId>yyzh-user-parent</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>yyzh-user-service</name>
<modules>
<module>yyzh-user-service</module>
<module>yyzh-user-api</module>
</modules>
<!-- 各模块属性变量统一在这里配置 -->
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<lombok.version>1.18.6</lombok.version>
<aspectj.version>1.9.6</aspectj.version>
<hutool.version>5.5.7</hutool.version>
<fastjson.version>1.2.75</fastjson.version>
<swagger.version>2.9.2</swagger.version>
<spring-cloud.version>Finchley.RC2</spring-cloud.version>
</properties>
<dependencies>
<!-- 支持web模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 测试模块 -->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-test</artifactId>-->
<!-- <scope>test</scope>-->
<!-- </dependency>-->
<!--Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<!-- hutool工具包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.7</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId> org.aspectj</groupId >-->
<!-- <artifactId> aspectjweaver</artifactId >-->
<!-- <version>${aspectj.version}</version >-->
<!-- </dependency>-->
<!-- 添加aop依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- 将swagger整合到spring boot项目中 -->
<!-- <dependency>-->
<!-- <groupId>io.springfox</groupId>-->
<!-- <artifactId>springfox-swagger2</artifactId>-->
<!-- <version>${swagger.version}</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>io.springfox</groupId>-->
<!-- <artifactId>springfox-swagger-ui</artifactId>-->
<!-- <version>${swagger.version}</version>-->
<!-- </dependency>-->
<!--配置文件处理器-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-configuration-processor</artifactId>-->
<!-- <optional>true</optional>-->
<!-- </dependency>-->
<!--监控和管理-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</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-netflix-hystrix</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-openfeign</artifactId>-->
<!-- </dependency>-->
</dependencies>
<!--管理spring cloud所有组件的版本-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 使用spring-boot-maven-plugin 来对Springboot 应用进行打包,需要在项目的 pom.xml 文件中引入插件 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
service层pom依赖注入
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>yyzh-user-parent</artifactId>
<groupId>com.yyzh.user</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yyzh-user-service</artifactId>
<version>1.0-SNAPSHOT</version>
<name>yyzh-user-service</name>
<!-- 各模块属性变量统一在这里配置 -->
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- 测试模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId> org.aspectj</groupId >
<artifactId> aspectjweaver</artifactId >
<version>${aspectj.version}</version >
</dependency>
<!-- 将swagger整合到spring boot项目中 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<!--配置文件处理器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</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-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<!-- 使用spring-boot-maven-plugin 来对Springboot 应用进行打包,需要在项目的 pom.xml 文件中引入插件 -->
<build>
<finalName>${project.name}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
api层pom依赖注入
<?xml version="1.0" encoding="UTF-8"?>
<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.yyzh.user</groupId>
<artifactId>yyzh-user-api</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>yyzh-user-api</name>
<!-- 各模块属性变量统一在这里配置 -->
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<openFeign.version>2.1.3.RELEASE</openFeign.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${openFeign.version}</version>
</dependency>
</dependencies>
<!-- 使用spring-boot-maven-plugin 来对Springboot 应用进行打包,需要在项目的 pom.xml 文件中引入插件 -->
<build>
<finalName>${project.name}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
service层application.yml
server:
port: 8521 #服务端口号
## actuator配置
management:
endpoints:
web:
exposure:
# 显式配置不需要权限验证对外开放的端点
include: "*"
# Actuator 的 Web 访问方式的根地址为 /actuator,可以通过 management.endpoints.web.base-path 参数进行修改
# base-path: /monitor
# 禁用所有执行器端点
# enabled: false
endpoint:
health:
enabled: true
show-details: always
# info:
# enabled: true
metrics:
enabled: true
sensitive: false
# JVM (Micrometer)要求给应用设置commonTag
metrics:
tags:
application: ${spring.application.name}
export:
prometheus:
enabled: true
# JSON 打印输出
spring:
jackson:
serialization:
indent_output: true
application:
name: user-server #服务名称--调用的时候根据名称来调用该服务的方法
#去掉重复的metrics
metrics:
servo:
enabled: false
# 更改Eureka更新频率将打破服务器的自我保护功能,生产环境下不建议自定义这些配置。
eureka:
instance:
prefer-ip-address: false #使用服务的id地址注册
lease-expiration-duration-in-seconds: 90 # 续约到期时间(默认90秒)
lease-renewal-interval-in-seconds: 30 # 续约更新时间间隔(默认30秒)
client:
healthcheck:
enabled: true # 开启健康检查(需要spring-boot-starter-actuator依赖)
register-with-eureka: true
registry-fetch-interval-seconds: 30
serviceUrl: #注册中心的注册地址
defaultZone: http://127.0.0.1:8761/eureka/
user-service层定义一个调用
package com.yyzh.user.controller;
import com.yyzh.user.service.HelloService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/v1/user")
@Api(value = "HelloUser", tags = "测试", description = "我看行")
public class HelloUser {
@Autowired
HelloService helloUserService;
@GetMapping(value = "/hello")
public String hello(@RequestParam("str") String str){
return helloUserService.hello(str);
}
}
user-service层启动类
新增一个注释@EnableDiscoveryClient,就是一个普通的Rest服务,不同的是我们需要将他注册到eureka server上面,方便后面的user-api中调用。
package com.yyzh.user;
import com.yyzh.user.properties.RootProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient // eureka客户端
@EnableDiscoveryClient // OpenFeignServer注册到eureka server
@SpringCloudApplication // 包括:@SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreaker
@EnableConfigurationProperties(RootProperties.class)
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
user-api层实现调用
使用@FeignClient注解一个interface 就标记成一个feign接口
package com.yyzh.user.api.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = "user-server")// 注册到eureka服务上的名字
@RequestMapping(path = "/v1/user")// 目标服务中拼接接口
public interface RemoteUserService {
@GetMapping(value = "/hello")
String hello(@RequestParam("str") String str);
}
user-api写完之后,别忘了maven-install一下打个包,这样可以被别的系统引入
然后就可以启动服务,下面来验证一下
客户端验证
在我们初始的服务中来验证,首先先引入刚刚打包好的user-api包
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.yyzh.user</groupId>
<artifactId>yyzh-user-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
启动类
增加@EnableFeignClients启用feign客户端
feing客户端配置FeighConfig.java
package com.springboot.demo.config;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Configuration;
/**
* @author zihui
* @version 1.0
* @title: FeighConfigurer
* @description: TODO
* @date 2021-01-21 15:36:25
*/
@Configuration
@EnableFeignClients(basePackages = {
"com.yyzh.user.api.feign"
})
public class FeighConfig {
}
使用feign
package com.springboot.demo.controller;
import com.yyzh.user.api.feign.RemoteUserService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("user")
@Api(value = "HelloUserController", tags = "测试用户", description = "我看行")
public class HelloUserController {
@Autowired
private RemoteUserService remoteUserService;
@GetMapping(value = "/hello")
public String hello(@RequestParam("str") String str){
return remoteUserService.hello(str);
}
}
启动客户端,效果如下
以上为feign基础用法,启用Fallback详见此链接