# 从浅入深 学习 SpringCloud 微服务架构(四)Ribbon

从浅入深 学习 SpringCloud 微服务架构(四)Ribbon

段子手168

一、ribbon 概述以及基于 ribbon 的远程调用。

1、ribbon 概述:

Ribbon 是 Netflixfa 发布的一个负载均衡器,有助于控制 HTTP 和 TCP客户端行为。

在 SpringCloud 中 Eureka 一般配合 Ribbon 进行使用,

Ribbon 提供了客户端负载均衡的功能,Ribbon 利用从 Eureka 中读取到的服务信息,

在调用服务节点提供的服务时,会合理的进行负载。

在 SpringCloud 中可以将注册中心和 Ribbon 配合使用,

Ribbon 自动的从注册中心中获取服务提供者的列表信息,并基于内置的负载均衡算法,请求服务。

2、Ribbon 的主要作用:

1)服务调用

基于 Ribbon 实现服务调用,是通过拉取到的所有服务列表组成(服务名-请求路径的)映射关系。

借助 RestTemplate 最终进行调用。

2)负载均衡

当有多个服务提供者时,Ribbon 可以根据负载均衡的算法自动的选择需要调用的服务地址。

3、修改 order_service 子工程(子模块)相关类

1)修改 order_service 子工程(子模块)中的 controller 类 OrderController.java

使用 基于 ribbon 的形式调用远程微服务,使用服务名称 service-product 替换 IP 地址 。

复制代码
/**
 *  C:\java-test\idea2019\spring_cloud_demo\order_service\src\main\java\djh\it\order\controller\OrderController.java
 *
 *  2024-4-19 订单的 controller 类 OrderController.java
 */
package djh.it.order.controller;

import djh.it.order.domain.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
@RequestMapping("/order")
public class OrderController {

    // 注入 restTemplate 对象
    @Autowired
    private RestTemplate restTemplate;

    /**
     *  注入 DiscoveryClient : springcloud 提供的获取元数据的工具类。
     *      调用方法获取服务的元数据信息。
     */
    @Autowired
    private DiscoveryClient discoveryClient;

    /**
     *  使用 基于 ribbon 的形式调用远程微服务:
     *  1、使用 @LoadBalanced 注解 声明 RestTemplate
     *  2、使用服务名称 service-product 替换 IP 地址 。
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
    public Product findById(@PathVariable Long id){
        Product product = null;
        //product = restTemplate.getForObject("http://127.0.0.1:9001/product/1", Product.class);
        product = restTemplate.getForObject("http://service-product/product/1", Product.class);
        return product;
    }


    /**
     *  参数:商品的 id
     *      通过订单系统,调用商品服务根据id查询商品信息。
     *          1)需要配置商品对象。
     *          2)需要调用商品服务。
     *   可以使用 java 中的 urlconnection, HttpClient, OkHttp 进行远程调用。
     *   也可以使用 restTemplate 进行远程调用。
     *
     * @param id
     * @return
     */
//    @RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
//    public Product findById(@PathVariable Long id){
//
//        //调用 discoveryClient 方法,已调用服务名称获取所有的元数据。
//        List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
//        for (ServiceInstance instance : instances) {
//            System.out.println(instance);
//        }
//
//        //获取唯一的一个元数据
//        ServiceInstance instance = instances.get(0);
//
//        Product product = null;
//
//        //根据元数据中的主机地址和端口号拼接请求微服务的 URL
//        product = restTemplate.getForObject("http://" + instance.getHost() + ":" + instance.getPort() + "/product/1", Product.class);
//
//
//        /**
//         *  调用商品服务(将微服务的请求路径硬编码到 java 代码中)
//         *  存在问题:对微服务调用的负载均衡,加入API网关,配置的统一管理,链路追踪。
//         */
//        //product = restTemplate.getForObject("http://127.0.0.1:9001/product/1", Product.class);
//        return product;
//    }
}

2)修改 order_service 子工程(子模块)中的 启动类 OrderApplication.java

使用 基于 ribbon 的形式调用远程微服务,使用 @LoadBalanced 注解 声明 RestTemplate。

复制代码
/**
 *   C:\java-test\idea2019\spring_cloud_demo\order_service\src\main\java\djh\it\order\OrderApplication.java
 *
 *   2024-4-19  启动类 OrderApplication.java
 */
package djh.it.order;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EntityScan("djh.it.order.domain")
@EnableEurekaClient  //激活 EurekaClient, 同 @EnableDiscoveryClient 注解相同。
public class OrderApplication {

    /**
     *  使用 spring 提供的 RestTemplate 发送 http 请求到商品服务。
     *      1)创建 RestTemplate 对象交给容器管理。
     *      2)在使用的时候,调用其方法完成操作(getXX, postXX)。     *
     */
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

3)运行 3个 启动类(order_service, product_service, eureka_service),进行测试

浏览器地址栏输入:http://localhost:9000 输出界面如下:

浏览器地址栏输入:http://localhost:9001/product/1 输出界面如下:

浏览器地址栏输入:http://localhost:9002/order/buy/1 输出界面如下:

二、ribbon:客户端负载均衡的概述

1、服务端的负载均衡:如:ngnix 软件系统, F5 硬件配置等。

2、客户端的负载均衡:如:ribbon 。

ribbon 是一个典型的客户端负载均衡器。

ribbon 会获取服务器的所有地址,根据内部的负载均衡算法,

获取本次请求的有效地址。

三、基于 ribbon 的负载均衡测试

1、准备两个商品微服务(product_service 子工程),端口分别为:9001,9011

1)修改 product_service 子工程(子模块)中的 controller 类 ProductController.java
复制代码
/**
 *  C:\java-test\idea2019\spring_cloud_demo\product_service\src\main\java\djh\it\product\controller\ProductController.java
 *
 *  2024-4-17 商品的 controller 类 ProductController.java
 */
package djh.it.product.controller;

import djh.it.product.domain.Product;
import djh.it.product.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private ProductService productService;


    //获取服务器端口号
    @Value("${server.port}")
    private String port;
    //获取服务器IP地址
    @Value("${spring.cloud.client.ip-address}")   //springcloud 自动获取当前应用的IP地址
    private String ip;

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public Product findById(@PathVariable Long id){
        Product product = productService.findById(id);
        product.setProductName("访问的服务地址是:" + ip + " : " + port);
        return product;
    }

    @RequestMapping(value = "", method = RequestMethod.POST)
    public String save (@RequestBody Product product){
        productService.save(product);
        return "保存成功";
    }

}
2)在 idea 的 RunDashboard 运行面板,复制一个 ProductApplication 并命名为:ProductApplication(2) 把它也运行起来。

在 idea 中,找不到 RunDashboard 运行面板 时,可以看如下文章:

# IDEA2019 如何打开 Run Dashboard 运行仪表面板

修改 product_service 子工程(子模块)中的 application.yml 配置文件中的端口号为:9011。

并把名为:ProductApplication(2) 服务 也运行起来。

复制代码
## C:\java-test\idea2019\spring_cloud_demo\product_service\src\main\resources\application.yml

server:
  port: 9001  # 启动端口 命令行注入。
#  port: ${port:56010}  # 启动端口设置为动态传参,如果未传参数,默认端口为 56010
#  servlet:
#    context-path: /application1

spring:
  application:
    name: service-product  #spring应用名, # 注意 FeignClient 不支持名字带下划线
#  main:
#    allow-bean-definition-overriding: true # SpringBoot2.1 需要设定。
  datasource:
    driver-class-name: com.mysql.jdbc.Driver  # mysql 驱动
#    url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8
    url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 12311
  jpa:
    database: MySQL
    show-sql: true
    open-in-view: true

eureka:  # 配置 Eureka
  client:
    service-url:
      defaultZone: http://localhost:9000/eureka/
#      defaultZone: http://localhost:9000/eureka/,http://localhost:8000/eureka/  # 高可用,注册多个 eurekaserver 用 , 隔开。
  instance:
    prefer-ip-address: true  # 使用 ip 地址注册
    instance-id: ${spring.cloud.client.ip-address}:${server.port}  # 向注册中心注册服务的id(IP 地址)。
    lease-renewal-interval-in-seconds: 10  # 设置向注册中心每10秒发送一次心跳,告诉注册中心此服务没有岩机,此参数默认是30秒。
    lease-expiration-duration-in-seconds: 20  # 设置每20秒如果注册中心没收到此服务的心跳,就认为此服务岩机了,此参数默认是90秒。


## C:\java-test\idea2019\spring_cloud_demo\product_service\src\main\resources\application.yml

server:
  port: 9011  # 启动端口 命令行注入。
#  port: ${port:56010}  # 启动端口设置为动态传参,如果未传参数,默认端口为 56010
#  servlet:
#    context-path: /application1

spring:
  application:
    name: service-product  #spring应用名, # 注意 FeignClient 不支持名字带下划线
#  main:
#    allow-bean-definition-overriding: true # SpringBoot2.1 需要设定。
  datasource:
    driver-class-name: com.mysql.jdbc.Driver  # mysql 驱动
#    url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8
    url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 12311
  jpa:
    database: MySQL
    show-sql: true
    open-in-view: true

eureka:  # 配置 Eureka
  client:
    service-url:
      defaultZone: http://localhost:9000/eureka/
#      defaultZone: http://localhost:9000/eureka/,http://localhost:8000/eureka/  # 高可用,注册多个 eurekaserver 用 , 隔开。
  instance:
    prefer-ip-address: true  # 使用 ip 地址注册
    instance-id: ${spring.cloud.client.ip-address}:${server.port}  # 向注册中心注册服务的id(IP 地址)。
    lease-renewal-interval-in-seconds: 10  # 设置向注册中心每10秒发送一次心跳,告诉注册中心此服务没有岩机,此参数默认是30秒。
    lease-expiration-duration-in-seconds: 20  # 设置每20秒如果注册中心没收到此服务的心跳,就认为此服务岩机了,此参数默认是90秒。
3)运行 3个 启动类(order_service, product_service, eureka_service),进行测试

浏览器地址栏输入:http://localhost:9000 输出界面如下:

浏览器地址栏输入:http://localhost:9001/product/1 输出界面如下:

浏览器地址栏输入:http://localhost:9011/product/1 输出界面如下:

浏览器地址栏输入:http://localhost:9002/order/buy/1 输出界面如下:

2、在订单系统中(order_service 子工程),远程以负载均衡的形式调用商品微服务。

1)在 order_service 子工程(子模块)的 controller 类 OrderController.java 中

使用 基于 ribbon 的形式调用远程微服务:使用服务名称 service-product 替换 IP 地址 。

复制代码
/**
 *  C:\java-test\idea2019\spring_cloud_demo\order_service\src\main\java\djh\it\order\controller\OrderController.java
 *
 *  2024-4-19 订单的 controller 类 OrderController.java
 */
package djh.it.order.controller;

import djh.it.order.domain.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
@RequestMapping("/order")
public class OrderController {

    // 注入 restTemplate 对象
    @Autowired
    private RestTemplate restTemplate;

    /**
     *  注入 DiscoveryClient : springcloud 提供的获取元数据的工具类。
     *      调用方法获取服务的元数据信息。
     */
    @Autowired
    private DiscoveryClient discoveryClient;

    /**
     *  使用 基于 ribbon 的形式调用远程微服务:
     *  1、使用 @LoadBalanced 注解 声明 RestTemplate
     *  2、使用服务名称 service-product 替换 IP 地址 。
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
    public Product findById(@PathVariable Long id){
        Product product = null;
        //product = restTemplate.getForObject("http://127.0.0.1:9001/product/1", Product.class);
        product = restTemplate.getForObject("http://service-product/product/1", Product.class);
        return product;
    }


    /**
     *  参数:商品的 id
     *      通过订单系统,调用商品服务根据id查询商品信息。
     *          1)需要配置商品对象。
     *          2)需要调用商品服务。
     *   可以使用 java 中的 urlconnection, HttpClient, OkHttp 进行远程调用。
     *   也可以使用 restTemplate 进行远程调用。
     *
     * @param id
     * @return
     */
//    @RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
//    public Product findById(@PathVariable Long id){
//
//        //调用 discoveryClient 方法,已调用服务名称获取所有的元数据。
//        List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
//        for (ServiceInstance instance : instances) {
//            System.out.println(instance);
//        }
//
//        //获取唯一的一个元数据
//        ServiceInstance instance = instances.get(0);
//
//        Product product = null;
//
//        //根据元数据中的主机地址和端口号拼接请求微服务的 URL
//        product = restTemplate.getForObject("http://" + instance.getHost() + ":" + instance.getPort() + "/product/1", Product.class);
//
//
//        /**
//         *  调用商品服务(将微服务的请求路径硬编码到 java 代码中)
//         *  存在问题:对微服务调用的负载均衡,加入API网关,配置的统一管理,链路追踪。
//         */
//        //product = restTemplate.getForObject("http://127.0.0.1:9001/product/1", Product.class);
//        return product;
//    }
}
2)在 order_service 子工程(子模块)的 启动类 OrderApplication.java 中

使用 基于 ribbon 的形式调用远程微服务:使用 @LoadBalanced 注解 声明 RestTemplate

复制代码
/**
 *   C:\java-test\idea2019\spring_cloud_demo\order_service\src\main\java\djh\it\order\OrderApplication.java
 *
 *   2024-4-19  启动类 OrderApplication.java
 */
package djh.it.order;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EntityScan("djh.it.order.domain")
@EnableEurekaClient  //激活 EurekaClient, 同 @EnableDiscoveryClient 注解相同。
public class OrderApplication {

    /**
     *  使用 spring 提供的 RestTemplate 发送 http 请求到商品服务。
     *      1)创建 RestTemplate 对象交给容器管理。
     *      2)在使用的时候,调用其方法完成操作(getXX, postXX)。     *
     */
    @LoadBalanced  //使用 基于 ribbon 的形式调用远程微服务:使用 @LoadBalanced 注解 声明 RestTemplate
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}
3)再次运行 3个 启动类(order_service, product_service, eureka_service),进行测试

浏览器地址栏输入:http://localhost:9002/order/buy/1 多刷新几次,

会发现,输出界面采用轮询的方式 切换 9001 和 9011 端口的访问。如下:

7.png

8.png

四、ribbon:负载均衡策略

1、ribbon:负载均衡策略 分类

com.netf1ix.1oadbalancer.RoundRobinRule: 以轮询的方式进行负载均衡

com.netflix.loadbalancer.RandomRule: 随机策略

com.netflix.1oadbalancer.RetryRule: 重试策略。

com.netflix.1oadbalancer.weightedResponseTimeRule: 权重策略。会计算每个服务的权重,越高的被调用的可能性越大。

com.netflix.1oadbalancer.BestAvailableRule: 最佳策略。遍历所有的服务实例,过滤掉故障实例,并返回请求数最小的实例返回。

com.netf1ix.1oadbalancer.Avai1abilityFi1teringRule: 可用过滤策略。过滤掉故障和请求数超过阈值的服务实例,再从剩下的实力中轮询调用。

2、ribbon:负载均衡 策略选择:

1)如果每个机器配置一样,则建议不修改策略(推荐)

2)如果部分机器配置性能强,则可以改为 WeightedResponseTimeRule 权重策略。

3、可以在服务消费者的 application.yml 配置文件中修改负载均衡策略

shop-service-product:

ribbon :

NFLoadBalancerRuleclassName: com.netflix.loadbalancer.RandomRule

1)修改 order_service 子工程(子模块)的 application.yml 配置文件,

添加 修改 ribbon 负载均衡策略。

复制代码
## C:\java-test\idea2019\spring_cloud_demo\order_service\src\main\resources\application.yml

server:
  port: 9002  # 启动端口 命令行注入。
#  port: ${port:9002}  # 启动端口设置为动态传参,如果未传参数,默认端口为 9002
#  servlet:
#    context-path: /application1

spring:
  application:
    name: service-order  #spring应用名, # 注意 FeignClient 不支持名字带下划线
#  main:
#    allow-bean-definition-overriding: true # SpringBoot2.1 需要设定。
  datasource:
    driver-class-name: com.mysql.jdbc.Driver  # mysql 驱动
#    url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8
    url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 12311
  jpa:
    database: MySQL
    show-sql: true
    open-in-view: true

eureka:  # 配置 Eureka
  client:
    service-url:
      defaultZone: http://localhost:9000/eureka/,http://localhost:8000/eureka/  # 多个 eurekaserver 用 , 隔开。
  instance:
    prefer-ip-address: true  # 使用 ip 地址注册
# 添加 修改 ribbon 负载均衡策略:服务名 - ribbon - NFLoadBalancerRuleclassName :策略
service-product:
  ribbon:
    NFLoadBalancerRuleclassName: com.netflix.loadbalancer.RandomRule
2)再次运行 3个 启动类(order_service, product_service, eureka_service),进行测试

浏览器地址栏输入:http://localhost:9002/order/buy/1 多刷新几次,

会发现,输出界面采用 随机 的方式 切换 9001 和 9011 端口的访问。如下:

五、ribbon:请求重试

1、修改 order_service 子工程(子模块)的 pom.xml 配置文件,

添加 spring-retry 请求重试 依赖坐标。

复制代码
<?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>spring_cloud_demo</artifactId>
        <groupId>djh.it</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>order_service</artifactId>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <!--            <version>5.1.32</version>-->
            <version>8.0.26</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- 引入 EurekaClient 依赖坐标 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入 spring-retry 请求重试 依赖坐标 -->
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
    </dependencies>

</project>
<!-- C:\java-test\idea2019\spring_cloud_demo\order_service\pom.xml -->

2、修改 order_service 子工程(子模块)的 application.yml 配置文件,

添加 ribbon 请求重试设置,添加 日志打印设置。

复制代码
## C:\java-test\idea2019\spring_cloud_demo\order_service\src\main\resources\application.yml

server:
  port: 9002  # 启动端口 命令行注入。
#  port: ${port:9002}  # 启动端口设置为动态传参,如果未传参数,默认端口为 9002
#  servlet:
#    context-path: /application1

spring:
  application:
    name: service-order  #spring应用名, # 注意 FeignClient 不支持名字带下划线
#  main:
#    allow-bean-definition-overriding: true # SpringBoot2.1 需要设定。
  datasource:
    driver-class-name: com.mysql.jdbc.Driver  # mysql 驱动
#    url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8
    url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 12311
  jpa:
    database: MySQL
    show-sql: true
    open-in-view: true

eureka:  # 配置 Eureka
  client:
    service-url:
      defaultZone: http://localhost:9000/eureka/,http://localhost:8000/eureka/  # 多个 eurekaserver 用 , 隔开。
  instance:
    prefer-ip-address: true  # 使用 ip 地址注册

logging:  # 使用日志
  level:
    root: debug

# 添加 修改 ribbon 负载均衡策略:服务名 - ribbon - NFLoadBalancerRuleclassName :策略
service-product:
  ribbon:
#    NFLoadBalancerRuleclassName: com.netflix.loadbalancer.RandomRule  # 配置负载均衡重置为随机
    ConnectTimeout: 250  # Ribbon 的连接超时时间
    ReadTimeout: 1000  # Ribbon 的数据读取超时时间
    OkToRetryOnAllOperations: true  # 是否对所有操作都进行重试
    MaxAutoRetriesNextServer: 1  # 切换实例的重试次数
    MaxAutoRetries: 1  # 对当前实例的重试次数。

3、再次运行 3个 启动类(order_service, product_service, eureka_service),进行测试

浏览器地址栏输入:http://localhost:9002/order/buy/1 多刷新几次,

先发现是轮询访问 9001 和 9011 端口,

然后停掉一个,再次刷新访问

会发现,edia 控制台 Consule 界面 有等待,尝试请求重试 日志,如下:

上一节链接如下:
# 从浅入深 学习 SpringCloud 微服务架构(三)注册中心 Eureka(4)

相关推荐
木易 士心1 分钟前
Spring AI 核心架构解析:构建企业级 AI 应用的 Java 新范式
java·spring
61900833611 分钟前
linux 安装jdk
java·linux·运维
懂得节能嘛.14 分钟前
【动态配置中心】Java+Redis构建动态配置中心
java·开发语言·redis
专注于大数据技术栈15 分钟前
Java中JDK、JRE、JVM概念
java·开发语言·jvm
YuanlongWang19 分钟前
C# 基础——值类型与引用类型的本质区别
java·jvm·c#
Kay_Liang44 分钟前
大语言模型如何精准调用函数—— Function Calling 系统笔记
java·大数据·spring boot·笔记·ai·langchain·tools
自由的疯1 小时前
Java 如何学习Docker
java·后端·架构
自由的疯1 小时前
Java Docker本地部署
java·后端·架构
007php0071 小时前
猿辅导Java面试真实经历与深度总结(二)
java·开发语言·python·计算机网络·面试·职场和发展·golang
摇滚侠1 小时前
Spring Boot 3零基础教程,WEB 开发 内容协商机制 笔记34
java·spring boot·笔记·缓存