SpringCloud-feign使用詳解
Feign
1、OpenFeign是什么
Feign是一個聲明式WebService客戶端。使用Feign能讓編寫Web Service客戶端更加簡單。它的使用方法是定義一個服務接口然后在上面添加注解。Feign也支持可拔插式的編碼器和解碼器。Spring Cloud對Feign進行了封裝,使其支持了Spring MVC標準注解和HttpMessageConverters。Feign可以與Eureka和Ribbon組合使用以支持負載均衡。

2、Feign能干什么
Feign旨在使編寫Java Http客戶端變得更容易。
使用Ribbon+RestTemplate時,利用RestTemplate對http請求的封裝處理,形成了一套模版化的調用方法。但是在實際開發(fā)中,由于對服務依賴的調用可能不止一處,往往一個接口會被多處調用,所以通常都會針對每個微服務自行封裝一些客戶端類來包裝這些依賴服務的調用。所以,F(xiàn)eign在此基礎上做了進一步封裝,由他來幫助我們定義和實現(xiàn)依賴服務接口的定義。在Feign的實現(xiàn)下,我們只需創(chuàng)建一個接口并使用注解的方式來配置它(以前是Dao接口上面標注Mapper注解,現(xiàn)在是一個微服務接口上面標注一個Feign注解即可),即可完成對服務提供方的接口綁定,簡化了使用Spring cloud Ribbon時,自動封裝服務調用客戶端的開發(fā)量。
3、Feign集成Ribbon
利用Ribbon維護了生產者的服務列表信息,并且通過輪詢實現(xiàn)了客戶端的負載均衡。而與Ribbon不同的是,通過feign只需要定義服務綁定接口且以聲明式的方法,優(yōu)雅而簡單的實現(xiàn)了服務調用。
4、Feign和OpenFeign的區(qū)別
Feign是Spring Cloud組件中的一個輕量級RESTful的HTTP服務客戶端Feign內置了Ribbon,用來做客戶端負載均衡,去調用服務注冊中心的服務。Feign的使用方式是:使用Feign的注解定義接口,調用這個接口,就可以調用服務注冊中心的服務。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>OpenFeign是Spring Cloud在Feign的基礎上支持了SpringMVC的注解,如@RequesMapping等等。OpenFeign的@Feignclient可以解析SpringMVc的@RequestMapping注解下的接口,并通過動態(tài)代理的方式產生實現(xiàn)類,實現(xiàn)類中做負載均衡并調用其他服務。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>5、Feign的簡單使用
1)OpenFeign的使用
1.添加依賴
<!-- openfeign 遠程調用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>2.編寫接口
@FeignClient注解
value值的要調用的微服務名稱
@FeignClient(value = "mall-order",path = "/order")
public interface OrderFeignService {
@RequestMapping("/findOrderByUserId/{userId}")
R findOrderByUserId(@PathVariable("userId") Integer userId);
}3.主啟動類添加注解
@EnableFeignClients
4.測試

2)Feign的使用
1.添加依賴
<!-- feign調用依賴 -->
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
<version>8.18.0</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
<version>8.18.0</version>
</dependency>2.編寫接口
public interface FeignDemo {
@Headers({"Content-Type: application/json","Accept: application/json"})
@RequestLine("GET /order/findOrderByUserId/{userId}")
R findOrderByUserId(@Param("userId") Integer userId);
}3.測試
public class FeignTest {
public static void main(String[] args) {
//基于json
// encoder指定對象編碼方式,decoder指定對象解碼方式
FeignDemo service = Feign.builder()
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.options(new Request.Options(1000, 3500))
//.retryer(new Retryer.Default(5000, 5000, 3))
.target(FeignDemo.class, "http://localhost:8020/");
System.out.println(service.findOrderByUserId(1));
}
}4.結果

6、OpenFeign自定義配置
1)日志配置
有時候我們遇到 Bug,比如接口調用失敗、參數(shù)沒收到等問題,或者想看看調用性能,就需要配置 Feign 的
日志了,以此讓 Feign 把請求信息輸出來。
OpenFeign日志等級有四種分別為
NONE:不輸出日志
BASIC:只輸出請求方法的 URL 和響應的狀態(tài)碼以及接口執(zhí)行的時間。
HEADERS:將 BASIC 信息和請求頭信息輸出。
FULL:輸出完整的請求信息。
方式一:全局配置
1.編寫配置類引入相關Bean
@Configuration
public class FeignConfig {
/**
* 日志級別
* 通過源碼可以看到日志等級有 4 種,分別是:
* NONE:不輸出日志。
* BASIC:只輸出請求方法的 URL 和響應的狀態(tài)碼以及接口執(zhí)行的時間。
* HEADERS:將 BASIC 信息和請求頭信息輸出。
* FULL:輸出完整的請求信息。
*
* @return
*/
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}2.修改配置文件
logging:
level:
com.tuling.mall.feigndemo.feign: debug #指定feign接口的路徑3.測試

方式二:局部配置
1.編寫配置(不能主啟動類掃描到),否則就成為了全局配置
@Configuration
public class FeignConfig {
/**
* 日志級別
* 通過源碼可以看到日志等級有 4 種,分別是:
* NONE:不輸出日志。
* BASIC:只輸出請求方法的 URL 和響應的狀態(tài)碼以及接口執(zhí)行的時間。
* HEADERS:將 BASIC 信息和請求頭信息輸出。
* FULL:輸出完整的請求信息。
*
* @return
*/
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}2.配置文件
logging: level: com.qianyue.mall.openFeign: debug
3.修改注解信息
@FeignClient(value = "mall-order",configuration = FeignConfig.class) //指定配置
public interface OrderFeignService {
@RequestMapping("/order/findOrderByUserId/{userId}")
R findOrderByUserId(@PathVariable("userId") Integer userId);
}說明:局部配置也可用通過配置文件方式配置
feign:
client:
config:
mall-account:
loggerLevel: FULL2)契約配置
Spring Cloud 在 Feign 的基礎上做了擴展,可以讓 Feign 支持 Spring MVC 的注解來調用。原生的 Feign 是不支持 Spring MVC 注解的,如果你想在 Spring Cloud 中使用原生的注解方式來定義客戶端也是 可以的,通過配置契約來改變這個配置,Spring Cloud 中默認的是 SpringMvcContract。
修改鍥約配置步驟如下:
1.修改契約配置,支持Feign原生的注解
@Bean
public Contract feignContract(){
return new Contract.Default();
}2.修改接口
此時將不再支持MVC的注解
@FeignClient(value = "mall-order")
public interface OrderFeignService {
@RequestLine("GET /order/findOrderByUserId/{userId}")
public R findOrderByUserId(@Param("userId") Integer userId);
}3.補充,也可用通過yml配置鍥約
feign:
client:
config:
mall-order:
loggerLevel: FULL
contract: feign.Contract.Default #指定Feign原生注解契約配置3)攔截器配置
通常我們調用的接口都是有權限控制的,很多時候可能認證的值是通過參數(shù)去傳遞的,還有就是通過請求頭 去傳遞認證信息,比如 Basic 認證方式。
方式一 Basic認證
1.在配置類直接配置Basic認證
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("qianyue", "123456");
}2.效果
調用接口會攜帶編碼后的認證去訪問接口

方式二 RequestInterceptor認證
每次 feign 發(fā)起http調用之前,會去執(zhí)行攔截器中的邏輯。
使用場景
- 統(tǒng)一添加 header 信息;
- 對 body 中的信息做修改或替換;
1.自定義攔截器實現(xiàn)認證邏輯
public class FeignAuthRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
// 業(yè)務邏輯 模擬認證邏輯
String access_token = UUID.randomUUID().toString();
template.header("Authorization",access_token);
}
}2.攔截器添加到容器中
@Bean
public FeignAuthRequestInterceptor feignAuthRequestInterceptor(){
return new FeignAuthRequestInterceptor();
}3.結果

4.也可用在yaml配置攔截器
feign:
client:
config:
mall-order:
requestInterceptors[0]: #配置攔截器
com.qianyue.mall.interceptor.FeignAuthRequestInterceptor4)超時時間配置
通過 Options 可以配置連接超時時間和讀取超時時間,Options 的第一個參數(shù)是連接的超時時間(ms), 默認值是 2s;第二個是請求處理的超時時間(ms),默認值是 5s。
@Bean
public Request.Options options(){
return new Request.Options(5000, 5000);
}或者是在yaml中配置
feign:
client:
config:
mall-order:
connectTimeout: 5000 # 連接超時時間,默認2s
readTimeout: 3000 #請求處理超時時間,默認5s補充說明: Feign的底層用的是Ribbon,但超時時間以Feign配置為準
5)客戶端組件配置
Feign 中默認使用 JDK 原生的 URLConnection 發(fā)送 HTTP 請求,我們可以集成別的組件來替換掉
URLConnection,比如 Apache HttpClient,OkHttp。
使用HttpClient
1.引入依賴
<!-- feign調用依賴 -->
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
<version>8.18.0</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
<version>8.18.0</version>
</dependency>
2.添加配置
feign:
httpclient:
enabled: true #其實默認就是true3.測試 會調用ApacheHttpClient的execute方法

使用okClient
1.引入依賴
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>2.修改yaml
feign:
httpclient:
enabled: false
okhttp:
enabled: true3.測試
會調用OkHttpClient的execute方法

關于這一塊的配置可用參考Feign的自動配置類FeignAutoConfiguration
6)壓縮配置
開啟壓縮可以有效節(jié)約網絡資源,提升接口性能,我們可以配置 GZIP 來壓縮數(shù)據(jù):
開啟配置
feign:
httpclient:
enabled: true
# okhttp:
# enabled: true
compression:
request:
enabled: true
# 配置壓縮的類型
mime-types: text/xml,application/xml,application/json
# 最小壓縮值
min-request-size: 2048
response:
enabled: true結果

注意:只有當 Feign 的 Http Client 不是 okhttp3 的時候,壓縮才會生效,配置源碼在 FeignAcceptGzipEncodingAutoConfiguration

7)編碼器解碼器
Feign 中提供了自定義的編碼解碼器設置,同時也提供了多種編碼器的實現(xiàn),比如 Gson、Jaxb、Jackson。 我們可以用不同的編碼解碼器來處理數(shù)據(jù)的傳輸。如果你想傳輸 XML 格式的數(shù)據(jù),可以自定義 XML 編碼解 碼器來實現(xiàn)獲取使用官方提供的 Jaxb
public interface Encoder {
void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeExcepti on;
}
public interface Decoder {
Object decode(Response response, Type type) throws IOException, DecodeException, FeignEx ception;
}JavaConfig配置
@Bean
public Decoder decoder(){
return new JacksonDecoder();
}
@Bean
public Encoder encoder(){
return new JacksonEncoder();
}YAML配置
feign:
client:
config:
mall-order:
encoder: feign.jackson.JacksonEncoder
decoder: feign.jackson.JacksonDecoder7、SpringCloud整合Dubbo
1)生產者服務抽離
新建一個api工程,存放我們的Dubbo接口 如下

public interface UserService {
List<User> list();
User getById(Integer id);
}2)生產者代碼
1.依賴
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.qianyue.mall</groupId>
<artifactId>mall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.qianyue.spring-cloud-alibaba</groupId>
<artifactId>mall-dubbo-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>2.yaml配置
dubbo:
scan:
base-packages: com.qianyue.mall.service #服務實現(xiàn)類的掃描基準包
protocol:
name: dubbo
port: -1
spring:
application:
name: mall-order-dubbo
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ms_order?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 199787
initial-size: 10
max-active: 100
min-idle: 10
max-wait: 60000
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
test-while-idle: true
test-on-borrow: false
test-on-return: false
stat-view-servlet:
enabled: true
url-pattern: /druid/*
filter:
stat:
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: false
wall:
config:
multi-statement-allow: true
main:
allow-bean-definition-overriding: true
cloud:
nacos:
discovery:
server-addr: 192.168.26.129
#mybatis-plus
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
#實體掃描,多個package用逗號或者分號分隔
typeAliasesPackage: com.qianyue.mall.entity
global-config:
#數(shù)據(jù)庫相關配置
db-config:
#主鍵類型 AUTO:"數(shù)據(jù)庫ID自增"
id-type: AUTO
logic-delete-value: -1
logic-not-delete-value: 0
banner: false
#原生配置
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
call-setters-on-nulls: true
jdbc-type-for-null: 'null'
server:
port: 8510
3.服務實現(xiàn)類
@DubboService
@Slf4j
public class UserServiceImpl implements UserService {
@Override
public List<User> list() {
log.info("查詢user列表");
List<User> list = new ArrayList<>();
return list;
}
@Override
public User getById(Integer id) {
return null;
}
}3)消費者代碼
1.引入依賴
dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.qianyue.mall</groupId>
<artifactId>mall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.qianyue.spring-cloud-alibaba</groupId>
<artifactId>mall-dubbo-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>2.yaml配置
dubbo:
cloud:
subscribed-services: mall-order-dubbo #指定訂閱的服務
protocol:
name: dubbo
port: -1
spring:
application:
name: mall-user-dubbo
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ms_order?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 199787
initial-size: 10
max-active: 100
min-idle: 10
max-wait: 60000
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
test-while-idle: true
test-on-borrow: false
test-on-return: false
stat-view-servlet:
enabled: true
url-pattern: /druid/*
filter:
stat:
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: false
wall:
config:
multi-statement-allow: true
main:
allow-bean-definition-overriding: true
cloud:
nacos:
discovery:
server-addr: 192.168.26.129
server:
port: 8610
3.服務調用
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
@DubboReference
UserService userService;
@RequestMapping("/findOrderByUserId/{userId}")
public User findOrderByUserId(@PathVariable("userId") Integer userId){
User user = userService.getById(userId);
return user;
}
}
總結
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Spring Cloud Zuul集成Swagger實現(xiàn)過程解析
這篇文章主要介紹了Spring Cloud Zuul集成Swagger實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-11-11
詳解@ConditionalOnMissingBean注解的作用
這篇文章主要介紹了詳解@ConditionalOnMissingBean注解的作用,@ConditionalOnMissingBean,它是修飾bean的一個注解,主要實現(xiàn)的是,當你的bean被注冊之后,如果而注冊相同類型的bean,就不會成功,它會保證你的bean只有一個,需要的朋友可以參考下2023-10-10
解決Error:(5, 28) java: 程序包org.apache.ibatis.io
這篇文章主要介紹了解決Error:(5, 28) java: 程序包org.apache.ibatis.io不存在問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05

