栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Cloud 之 Feign

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Cloud 之 Feign

文章目录
  • 前言
  • 一、理论部分
    • 1、Feign原理简述
    • 2、FeignClient注解的一些属性
    • 3、Feign配置底层请求client
    • 4、Feign开启GZIP压缩
    • 5、Feign Client上的配置方式
    • 6、Feign Client开启日志
    • 7、Feign 的GET的多参数传递
  • 二、实战部分
    • 1、创建feign-service模块
    • 2、引入依赖包
    • 3、编写控制层
    • 4、编写服务层
    • 5、编写实现服务降级功能的类
    • 6、启动类配置
    • 7、在application.properties文件中配置
    • 8、启动服务测试
  • 总结


前言

Spring Cloud OpenFeign 是声明式的服务调用工具,它整合了Ribbon和Hystrix,拥有负载均衡和服务容错功能。本文开始学习对OpenFeign的使用。

一、理论部分 1、Feign原理简述
  • 启动时,程序会进行包扫描,扫描所有包下所有@FeignClient注解的类,并将这些类注入到spring的IOC容器中。当定义的Feign中的接口被调用时,通过JDK的动态代理来生成RequestTemplate。
  • RequestTemplate中包含请求的所有信息,如请求参数,请求URL等。
  • RequestTemplate声成Request,然后将Request交给client处理,这个client默认是JDK的HTTPUrlConnection,也可以是OKhttp、Apache的HTTPClient等。
  • 最后client封装成LoadBaLanceClient,结合ribbon负载均衡地发起调用。
2、FeignClient注解的一些属性
属性名默认值作用备注
value空字符串调用服务名称,和name属性相同
serviceId空字符串服务id,作用和name属性相同已过期
name空字符串调用服务名称,和value属性相同
url空字符串全路径地址或hostname,http或https可选
decode404false配置响应状态码为404时是否应该抛出FeignExceptions
configuration{}自定义当前feign client的一些配置 参考FeignClientsConfiguration
fallbackvoid.class熔断机制,调用失败时,走的一些回退方法,可以用来抛出异常或给出默认返回数据。底层依赖hystrix,启动类要加上@EnableHystrix
path空字符串自动给所有方法的requestMapping前加上前缀,类似与controller类上的requestMapping
primarytrue
3、Feign配置底层请求client
feign.client.config.default.connect-timeout=5000
feign.client.config.default.read-timeout=5000
feign.client.config.default.logger-level=basic
#开启Okhttp请求
feign.okhttp.enabled=true
#在Feign中开启Hystrix
feign.hystrix.enabled=true
4、Feign开启GZIP压缩
#开启请求数据压缩
feign.compression.request.enabled=true
#开启支持压缩的MIME TYPE
feign.compression.request.mime-types=text/xml,application/xml,application/json
#开启响应GZIP压缩
feign.compression.response.enabled=true
#配置压缩数据大小的下限
feign.compression.request.min-request-size=2048

**注:**由于开启GZIP压缩之后,Feign之间的调用数据通过二进制协议进行传输,返回值需要修改为ResponseEntity才可以正常显示,否则会导致服务之间的调用乱码。

示例:

@PostMapping("/order/{productId}")
ResponseEntity addCart(@PathVariable("productId") Long productId);
5、Feign Client上的配置方式

方式一:通过java bean 的方式指定。

@EnableFeignClients注解上有个defaultConfiguration属性,可以指定默认Feign Client的一些配置。

@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
@Configuration
public class DefaultFeignConfiguration {

    @Bean
    public Retryer feignRetryer() {
        return new Retryer.Default(1000,3000,3);
    }
}

方式二:通过配置文件方式指定。

#连接超时
feign.client.config.default.connect-timeout=5000
#读取超时
feign.client.config.default.read-timeout=5000
#日志等级
feign.client.config.default.logger-level=basic
6、Feign Client开启日志

方式一:通过java bean的方式指定

@Configuration
public class DefaultFeignConfiguration {
    @Bean
    public Logger.Level feignLoggerLevel(){
        return Logger.Level.BASIC;
    }
}

方式二:通过配置文件指定

7、Feign 的GET的多参数传递

目前,feign不支持GET请求直接传递POJO对象的,目前解决方法如下:

  1. 把POJO拆散城一个一个单独的属性放在方法参数中
  2. 把方法参数编程Map传递
  3. 使用GET传递@RequestBody,但此方式违反restful风格

实战示例:
通过feign的拦截器来实现。

@Component
@Slf4j
public class FeignCustomRequestInteceptor implements RequestInterceptor {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void apply(RequestTemplate template) {
        if (HttpMethod.GET.toString() == template.method() && template.body() != null) {
            //feign 不支持GET方法传输POJO 转换成json,再换成query
            try {
                Map> map = objectMapper.readValue(template.bodyTemplate(), new TypeReference>>() {

                });
                template.body(null);
                template.queries(map);
            } catch (IOException e) {
                log.error("cause exception", e);
            }
        }
    }
二、实战部分 1、创建feign-service模块 2、引入依赖包


    
        eureka
        com.hjl
        1.0-SNAPSHOT
    
    4.0.0

    feign-service

    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        

    


3、编写控制层
package com.hjl.feign.controller;

import com.hjl.feign.pojo.Result;
import com.hjl.feign.pojo.User;
import com.hjl.feign.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;


@RestController
@RequestMapping("/user")
public class UserFeignController {

    @Autowired
    private UserService userService;

    @PostMapping("/insert")
    public Result insert(@RequestBody User user) {
        return userService.insert(user);
    }

    @GetMapping("/{id}")
    public Result getUser(@PathVariable Long id) {
        return userService.getUser(id);
    }

    @GetMapping("/listUsersByIds")
    public Result> listUsersByIds(@RequestParam List ids) {
        return userService.listUsersByIds(ids);
    }

    @GetMapping("/getByUsername")
    public Result getByUsername(@RequestParam String username) {
        return userService.getByUsername(username);
    }

    @PostMapping("/update")
    public Result update(@RequestBody User user) {
        return userService.update(user);
    }

    @PostMapping("/delete/{id}")
    public Result delete(@PathVariable Long id) {
        return userService.delete(id);
    }

}
4、编写服务层
package com.hjl.feign.service;

import com.hjl.feign.pojo.Result;
import com.hjl.feign.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

import java.util.List;


@FeignClient(value = "user-service", fallback = UserFallbackService.class)
public interface UserService {

    @PostMapping("/user/insert")
    Result insert(@RequestBody User user);

    @GetMapping("/user/{id}")
    Result getUser(@PathVariable Long id);

    @GetMapping("/user/listUsersByIds")
    Result> listUsersByIds(@RequestParam List ids);

    @GetMapping("/user/getByUsername")
    Result getByUsername(@RequestParam String username);

    @PostMapping("/user/update")
    Result update(@RequestBody User user);

    @PostMapping("/user/delete/{id}")
    Result delete(@PathVariable Long id);

}

通过@FeignClient(value = “user-service”, fallback = UserFallbackService.class)注解完成feign的服务配置。
value属性执行远程调用的服务;
fallback 属性指定服务降级的具体实现类。

5、编写实现服务降级功能的类
package com.hjl.feign.service;

import com.hjl.feign.pojo.Result;
import com.hjl.feign.pojo.User;
import org.springframework.stereotype.Component;

import java.util.List;


@Component
public class UserFallbackService implements UserService {

    @Override
    public Result insert(User user) {
        return new Result("调用失败,服务被降级",500);
    }

    @Override
    public Result getUser(Long id) {
        return new Result("调用失败,服务被降级",500);
    }

    @Override
    public Result> listUsersByIds(List ids) {
        return new Result("调用失败,服务被降级",500);
    }

    @Override
    public Result getByUsername(String username) {
        return new Result("调用失败,服务被降级",500);
    }

    @Override
    public Result update(User user) {
        return new Result("调用失败,服务被降级",500);
    }

    @Override
    public Result delete(Long id) {
        return new Result("调用失败,服务被降级",500);
    }

}
6、启动类配置
  • 添加@EnableFeignClients注解
  • 添加@EnableEurekaClient注解

feign组件的底层通过ribbon实现了负载均衡功能,需要依赖eureka功能完成服务地址的查找。

package com.hjl.feign;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;



@EnableEurekaClient
@EnableFeignClients
@SpringBootApplication
public class FeignServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(FeignServiceApplication.class,args);
    }
}
7、在application.properties文件中配置
#服务端口
server.port=1009

#服务名称
spring.application.name=feign-service

#############################eureka相关配置###################################
#开启服务注册
eureka.client.register-with-eureka=true
#开启从服务注册中心获取服务地址的功能
eureka.client.fetch-registry=true
#指定服务注册中心地址
eureka.client.service-url.defaultZone=http://root:root@localhost:1001/eureka,http://root:root@localhost:1010/eureka
        

##############################feign相关配置##################################
#连接超时
feign.client.config.default.connect-timeout=5000
#读取超时
feign.client.config.default.read-timeout=5000
#日志等级
feign.client.config.default.logger-level=basic
#开启Okhttp请求
feign.okhttp.enabled=true
#在Feign中开启Hystrix
feign.hystrix.enabled=true
#开启请求数据压缩
feign.compression.request.enabled=true
#开启支持压缩的MIME TYPE
feign.compression.request.mime-types=text/xml,application/xml,application/json
#开启响应GZIP压缩
feign.compression.response.enabled=true
#配置压缩数据大小的下限
feign.compression.request.min-request-size=2048

#配置远程调用服务-用户服务
service-url.user-service=http://user-service

关于Hystrix启动配置说明:
1、Spring Cloud 2020之前的版本,只需在配置文件中设置feign.hystrix.enabled=true;
2、Spring Cloud 2020之后的版本,feign.hystrix.enabled=true无法解析,需要配置:feign.circuitbreaker.enabled=true。

8、启动服务测试

在注册中心查看服务

表明服务已经成功注册。
访问feign-service服务端口多次调用服务:http://127.0.0.1:1009/user/1,


表明负载均衡功能已经生效。

对feign中的服务降级功能进行测试,关闭user-service服务后,再次请求接口,服务请求已经完成服务降级处理;

总结

Feign是声明式的服务调用工具,我们只需创建一个接口并用注解的方式来配置它,就可以实现对某个服务接口的调用,简化了直接使用RestTemplate来调用服务接口的开发量。Feign具备可插拔的注解支持,同时支持Feign注解、JAX-RS注解及SpringMvc注解。当使用Feign时,Spring Cloud集成了Ribbon和Eureka以提供负载均衡的服务调用及基于Hystrix的服务容错保护功能。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/685826.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号