IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Feign 微服务调用 (nacos 作为注册中心) -> 正文阅读

[Java知识库]Feign 微服务调用 (nacos 作为注册中心)

Feign 微服务调用 (nacos 作为注册中心)

Feign 是 spring Cloud Netflix 组件中的一量级 Restful的HTTP 服务客户端,实现了负载均衡和 Rest 调用的开源框架,封装了RibbonRestTemplate,实现WebService的面向接口编程。

Feign 简化了RestTemplate代码,是声明式服务调用组件:核心就是像调用本地方法一样调用远程方法。让开发者无需关注,远程调用过程,和交互细节。

Feign 本身并不支持spring MVC注解,它有一套自己的注解,为了更方便使用Spring Cloud孵化OpenFeign。并且支持spring mvc的注解,例如:@RequestMapping、@PathVariable。

openFeign 的@FeignClient可以解析Spring MVC@RequestMapping注解下的接口,并通过动态代理方式产生实现类,实现类中做负载均衡调用服务。

soringboot 2.0 以后基本使用 OpenFeign

官网

特性

  • Hystrix 和它的 Fallback
  • HTTP 请求响应的压缩
  • Ribbon 负载均衡客户端
  • 可拔插的HTTP编码器和解码器
  • 拔插的注解支持,包括Feign 注解 和JAX-RS 注解

快速开始

项目预览

image-20220507201640659

项目

pom 文件

父项目

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <!-- 利用传递依赖,公共部分 -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>
    </dependencies>

    <!-- 管理依赖 -->
    <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>

    <!--注意:这里需要添加以下配置,否则可能会有各种依赖问题 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

goods 消费者

    <parent>
        <artifactId>springcloud-openfeig</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>openfeig-goods</artifactId>
    <description>商品服务</description>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

order 生产者

    <parent>
        <artifactId>springcloud-openfeig</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>openfeig-order</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
<!--        openfeign 依赖的 服务调用 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

goods

server:
  port: 8081
spring:
  application:
    name: openfeig-goods
  cloud:
    nacos:
      server-addr: ...:8848
@RestController
public class GoodsController {

    @GetMapping("hello/{message}")
    public String hello(@PathVariable String message){
        return "来自goods的消息 =="+ message;
    }
}

order

server:
  port: 8080
spring:
  application:
    name: openfeig-order
  cloud:
    nacos:
      server-addr: ....:8848
@SpringBootApplication
//开启远程调用的注解 扫描,可以扫描 @FeignClient
@EnableFeignClients
public class OpenFeigOrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OpenFeigOrderApplication.class,args);
    }
}
// 准备远程调用的接口
@FeignClient(name = "openfeig-goods")
public interface  GoodsClienService {

    @GetMapping("hello/{message}")
    String hello(@PathVariable String message);
}
//提供对外暴露的 api
@RestController
public class OrderController  {

    //nacos 客户端信息
    @Autowired
    private LoadBalancerClient loadBalancerClient;

    //调用的 service
    @Autowired
    private GoodsClienService cartService;

    @GetMapping("add/{message}")
    public String add(@PathVariable String message){
        ServiceInstance choose = loadBalancerClient.choose("openfeig-goods");
        return cartService.hello(message) +"  "+ choose.getHost() + "--" + choose.getPort();
    }
}

测试

image-20220507202450084

@FeignClient ??

需要 @EnableFeignClients来开启扫描

当定义的Feign接口中的方法被调用时,通过JDK的代理方式,生成具体的 RequestTemplate。这个对象中,封装了http需要的全部信息。参数、方法名等等

属性说明
name指定FeignClient等名称,如果项目使用了Ribbon,那么name属性会作为微服务等名称,用于服务发现
url一般用于调试,可以手动指定@FeignClient调用的服务地址
decode404当发生404错误时,如果该字段值为true,会调用decoder进行编码,否则抛出FeignException
configurationFeign 配置列,可以自定义Feign 的 Encoder、Decoder、LogLevel、Contract
也可以在配置文件中配置
fallback定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现 @FeignClient标记的接口
fallbackFactory工厂类,用于生成fallback类实例,通过这个属性可以实现每个接口通用的容错逻辑,减少重复的代码
path定义当前FeignClient 的统一前缀

Feign 日志开启

需要在配置文件中 logback.xml 把日志级别改为debug

# open feign 日志设置
logging:
  level:
    com.springcloud.study.service.ProviderClientService: debug
//全局的配置 日志配置类
@Configuration
public class FeignServiceConfig {

    /*
    Logger.Level 设置级别
    NONE : 不记录任何信息
    BASIC: 仅记录请求方法,URL以及响应状态码
    HEADERS: 除了记录 BASIC级别信息外,还会记录请求和响应的头信息
    FULL: 记录所有的请求于响应的明细,包括头信息,请求体,元数据
     */
    @Bean
    Logger.Level feignLogger(){
        return Logger.Level.FULL;
    }
}
//指定单独的配置 MyFeignConfig 是一个 日志的配置类
@FeignClient(configurtion = MyFeignConfig.class)

HTTP Client 替换

Feign 默认使用的是JDK原生的 URLConnection发送HTTP请求,没有用链接池。对每个地址都会建立一个长链接。

feign 的HTTP客户端支持3中框架HttpURLConnection、HttpClient、OkHttp

默认是 HttpURLConnection

修改

<!-- feign httpclient -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

<!-- 或者换成okhttp -->
<!-- 引入 Feign 对 Okhttp 的支持 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>
feign:
  httpclient:
    # 开启httpclient
    enabled: true

如果使用 okhttp 的可以自定义配置

okHttp 优势

  1. 支持SPDY,合并多个请求到同一个主机
  2. 使用链接池
  3. 使用GZIP压缩减少传输数据体积
  4. 缓存响应结果,减少重复请求
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {

    @Bean
    public okhttp3.OkHttpClient okHttpClient() {
        return new OkHttpClient.Builder()
                .connectTimeout(60, TimeUnit.SECONDS) //链接超时时间
                .readTimeout(60,TimeUnit.SECONDS)     //读超时
                .writeTimeout(60,TimeUnit.SECONDS)     //写超时
                .retryOnConnectionFailure(true)                 //自动重试
                .connectionPool(new ConnectionPool())           //创建链接池 okhttp包的
                .build();
    }
}

参数传递

get 方式,@PathVariable、@RequestParm注解来接收

post 方式 ,@RequestBody接收请求参数

特殊需求,Get方法传递了多参数

需要时实现Feign 的RequestInterceptor中的pally进行统一处理

TODO 还是用 post 方法发送省事

实现Token 传递

认证鉴权的时候,使用JWT,或spring security 都需要拿到token

RequestInterceptor 拦截器,在feign 调用的时候,向请求头里添加需要传递的token

基于上面的代码改动 注意token 大小写的问题

//生产端
@Component
public class FeignTokenAddInterceptor  implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate requestTemplate) {
        if(null==getHttpServletRequest()){
            //此处省略日志记录
            return;
        }
        //将获取Token对应的值往下面传
        requestTemplate.header("oauthToken", getHeaders(getHttpServletRequest()).get("oauthtoken"));
    }

    private HttpServletRequest getHttpServletRequest() {
        try {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Feign拦截器拦截请求获取Token对应的值
     * @param request
     * @return
     */
    private Map<String, String> getHeaders(HttpServletRequest request) {
        Map<String, String> map = new LinkedHashMap<>();
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String key = enumeration.nextElement();
            String value = request.getHeader(key);
            map.put(key, value);
        }

        System.out.println("模拟token " +  map.get("oauthtoken"));

        return map;
    }
}

    @GetMapping("hello/{message}")
    public String hello(@PathVariable("message") String message, HttpServletRequest req){

        String oauthToken = req.getHeader("oauthToken");
        System.out.println( "token =" + oauthToken);

        return "来自goods的消息 =="+ message + oauthToken;
    }

image-20220508153045445

底部

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 12:26:14  更:2022-05-09 12:29:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:29:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码