远程调用总结

远程调用的作用

在原来的springboot项目中通常是通过调用业务层来实现一个功能。在微服务中由于我们将许多业务进行一个拆开,但是我们需要其他业务层的数据所以就需要通过发送请求的方式来获取数据

实现注册中心nacos(第一步)

我们基于Docker来部署Nacos的注册中心,首先我们要准备MySQL数据库表,用来存储Nacos的数据。由于是Docker部署,所以大家需要将资料中的SQL文件导入到你Docker中的MySQL容器中:

其中的nacos/custom.env文件中,有一个MYSQL_SERVICE_HOST也就是mysql地址,需要修改为你自己的虚拟机IP地址:

然后,将课前资料中的nacos目录上传至虚拟机的/root目录。

进入root目录,然后执行下面的docker命令:

bash 复制代码
docker run -d \
--name nacos \
--env-file ./nacos/custom.env \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
--restart=always \
nacos/nacos-server:v2.1.0-slim

值得注意的是:当我们电脑的ip地址改变的时候 需要通过将nacos从docker中进行移除,重新通过docker进行run,同时别忘忘记将nacos/custom.env中的ip进行修改

启动完成后,访问下面地址:http://192.168.150.101:8848/nacos/,注意将192.168.150.101替换为你自己的虚拟机IP地址。

首次访问会跳转到登录页,账号密码都是nacos

服务注册

将一个模块注册到nacos注册中心的步骤如下

1.引入依赖

2.配置nacos地址

添加依赖

在需要实现nacos的模块中的pom文件中添加一下依赖

html 复制代码
<!--nacos 服务注册发现-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

配置Nacos

在yml文件添加nacos的地址配置

XML 复制代码
spring:
  application:
    name: item-service # 服务名称
  cloud:
    nacos:
      server-addr: 192.168.150.101:8848 # nacos地址

然后我们访问 http:虚拟机地址:8848/nacos/

看是否可以登录进去,如果可以登录进去就代表成功

服务发现

服务的消费者要去nacos订阅服务,这个过程就是服务发现,步骤如下:

  • 引入依赖

  • 配置Nacos地址

  • 发现并调用服务

引入依赖

服务发现除了要引入nacos依赖以外,由于还需要负载均衡,因此要引入SpringCloud提供的LoadBalancer依赖。

在消费者中模块中添加一下依赖

html 复制代码
<!--nacos 服务注册发现-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

这样消费者还有生产者都全部确定

OpenFegin(第二步)

快速使用

引入依赖

在微服务的pom.xml中引入OpenFeign的依赖和loadBalancer依赖:

html 复制代码
  <!--openFeign-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
  </dependency>
  <!--负载均衡器-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-loadbalancer</artifactId>
  </dependency>

启用OpenFegin

接下来,我们在cart-serviceCartApplication启动类上添加注解,启动OpenFeign功能:

"@EnableFeignClients" 这个注解就是气筒OpenFegin服务的注解

java 复制代码
package com.hmall.cart;

import com.hmall.api.config.DefaultFeignConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableFeignClients(basePackages = "com.hmall.api.client",defaultConfiguration = DefaultFeignConfig.class)
@MapperScan("com.hmall.cart.mapper")
@SpringBootApplication
public class CartApplication {
    public static void main(String[] args) {
        SpringApplication.run(CartApplication.class, args);
    }
}

编写OpenFeign客户端

cart-service(这个服务是一个例子)中,定义一个新的接口,编写Feign客户端(现在是在cart包中,后面需要将统一写在api模块中):

其中代码如下:

java 复制代码
package com.hmall.cart.client;

import com.hmall.cart.domain.dto.ItemDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@FeignClient("item-service")
public interface ItemClient {

    @GetMapping("/items")
    List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}

这里只需要声明接口,无需实现方法。接口中的几个关键信息:

  • @FeignClient("item-service") :声明服务名称

  • @GetMapping :声明请求方式

  • @GetMapping("/items") :声明请求路径

  • @RequestParam("ids") Collection<Long> ids :声明请求参数

  • List<ItemDTO> :返回值类型

在这里我们需要搞清楚消费者和生产者:

我们是将item-service中的服务进行注册,也就是item-service是生产者

cart-service是消费者

有了上述信息,OpenFeign就可以利用动态代理帮我们实现这个方法,并且向http://item-service/items发送一个GET请求,携带ids为请求参数,并自动将返回值处理为List<ItemDTO>

我们只需要直接调用这个方法,即可实现远程调用了。

使用FeignClient

最后,我们在cart-servicecom.hmall.cart.service.impl.CartServiceImpl中改造代码,直接调用ItemClient的方法:

连接池

Feign底层发起http请求,依赖于其它的框架。其底层支持的http客户端实现包括:

  • HttpURLConnection:默认实现,不支持连接池

  • Apache HttpClient :支持连接池

  • OKHttp:支持连接池

因此我们通常会使用带有连接池的客户端来代替默认的HttpURLConnection。比如,我们使用OK Http.

引入依赖

cart-servicepom.xml中引入依赖(值得注意的是我们是在消费者这边引入依赖):

html 复制代码
<!--OK http 的依赖 -->
<dependency>
  <groupId>io.github.openfeign</groupId>
  <artifactId>feign-okhttp</artifactId>
</dependency>

开启连接池

cart-serviceapplication.yml配置文件中开启Feign的连接池功能(值得注意的是我们也是在消费者这边开启连接池功能):

html 复制代码
feign:
  okhttp:
    enabled: true # 开启OKHttp功能

重启服务,连接池就生效了。

最佳实践(其就是将消费者client转移统一的模块)

相信大家都能想到,避免重复编码的办法就是抽取。不过这里有两种抽取思路:

  • 思路1:抽取到微服务之外的公共module

  • 思路2:每个微服务自己抽取一个module

如图:

方案1抽取更加简单,工程结构也比较清晰,但缺点是整个项目耦合度偏高。

方案2抽取相对麻烦,工程结构相对更复杂,但服务之间耦合度降低。

由于item-service已经创建好,无法继续拆分,因此这里我们采用方案1.

抽取Fegin客户端

在自己的父项目定义新的的moduie,命名为xxx-api (由于在黑马上学习的,所以名为hm-api)

其依赖如下:

html 复制代码
<?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>hmall</artifactId>
        <groupId>com.heima</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>hm-api</artifactId>

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

    <dependencies>
        <!--open feign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- load balancer-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <!-- swagger 注解依赖 -->
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.6.6</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

现在,任何微服务要调用item-service(原来的没有进行拆解的项目)中的接口,只需要引入hm-api模块依赖即可,无需自己编写Feign客户端了。

扫描包

接下来,我们在cart-service(消费者)pom.xml中引入hm-api模块:

html 复制代码
  <!--feign模块-->
  <dependency>
      <groupId>com.heima</groupId>
      <artifactId>hm-api</artifactId>
      <version>1.0.0</version>
  </dependency>

在这里需要注意的是由于我们将client(装有可以远程调用的client放在api)所以在启动的时候回扫描不到,所以我们需要在消费者启动类的

@EnableFeignClients(basePackages = "com.hmall.api.client")

中加上client中的包 就是像上面那样。

相关推荐
阿里云云原生14 小时前
LLM 不断提升智能下限,MCP 不断提升创意上限
云原生
阿里云云原生15 小时前
GraalVM 24 正式发布阿里巴巴贡献重要特性 —— 支持 Java Agent 插桩
云原生
云上艺旅18 小时前
K8S学习之基础七十四:部署在线书店bookinfo
学习·云原生·容器·kubernetes
程序员 小柴1 天前
docker的与使用
java·docker·eureka
云上艺旅1 天前
K8S学习之基础六十八:Rancher创建deployments资源
学习·云原生·容器·kubernetes·rancher
rider1891 天前
【4】搭建k8s集群系列(二进制部署)之安装master节点服务(kube-apiserver)
云原生·容器·kubernetes
GreenMountainEcho1 天前
Kubernetes 入门篇之 Node 安装与部署
云原生·容器·kubernetes
alden_ygq1 天前
k8s statefulset pod重启顺序
云原生·容器·kubernetes
bjzhang752 天前
微服务组件——Eureka组件的安装与使用指南
微服务·eureka
云上艺旅2 天前
K8S学习之基础七十二:Ingress基于Https代理pod
学习·云原生·容器·https·kubernetes