SpringCloud之负载均衡Ribbon问题及解读

 更新时间:2026年05月12日 16:49:11   作者:一心同学  
本文介绍了负载均衡的基本概念,分类,重点讲述了SpringCloud中的Ribbon的的负载均衡的使用和使用,并详细描述了Ribbon的的每种算法的具体实现用,如轮询、随机、重试等

一、什么是负载均衡?

负载均衡(Load Balance),意思是将负载(工作任务,访问请求)进行平衡、分摊到多个操作单元(服务器,组件)上进行执行。是解决高性能,单点故障(高可用),扩展性(水平伸缩)的终极解决方案。

例子:

在早高峰乘地铁时候,紧挨小区的地铁口人特别多,一般会有限流,还会有个地铁工作人员Y用那个大喇叭在喊“着急的人员请走B口,B口人少车空”。。。

而这个地铁工作人员Y就是负责负载均衡的为了提升网站的各方面能力,我们一般会把多台机器组成一个集群对外提供服务。然而,我们的网站对外提供的访问入口都是一个的,比如www.taobao.com。那么当用户在浏览器输入www.taobao.com的时候如何将用户的请求分发到集群中不同的机器上呢,这就是负载均衡在做的事情。

二、负载均衡分类

注:LB,即负载均衡 (LoadBalancer)

2.1  集中式LB

即在服务的提供方消费方之间使用独立的LB设施,如Nginx(反向代理服务器),由该设施负责把访问请求通过某种策略转发至服务的提供方!

2.2  进程式 LB

将LB逻辑集成到消费方消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。

Ribbon 就属于进程式LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址!

三、Spring Cloud Ribbon是什么?

(1)Ribbon负责实现客户端的负载均衡,负载均衡器提供很多对http和tcp的行为控制。

(2)Ribbon默认提供了很多负载均衡算法,如:轮询、随机等,也可以实现自定义的负载均衡算法

(3)在Spring cloud中,当Ribbon与Eureka结合使用时,Ribbon可以自动的从Eureka Server获取服务列表,基于负载均衡算法,进行服务调用。

(4)在Spring Cloud构建的微服务系统中,Ribbon作为客户端负载均衡器,有两种使用方式,第一种是和RestTemplate相结合,第二种是和Feign相结合。

四、Ribbon 的负载均衡算法

(1)RoundRobinRule:轮询策略,默认策略。

(2)RandomRule,随机,使用Random对象从服务列表中随机选择一个服务。

(3)RetryRule,轮询 + 重试。

(4)WeightedResponseTimeRule:优先选择响应时间快,此策略会根据平均响应时间计算所有服务的权重,响应时间越快,服务权重越重、被选中的概率越高。此类有个DynamicServerWeightTask的定时任务,默认情况下每隔30秒会计算一次各个服务实例的权重。刚启动时,如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够,会切换回来。

(5)AvailabilityFilteringRul:,可用性过滤,会先过滤掉以下服务:由于多次访问故障而断路器处于打开的服务、并发的连接数量超过阈值,然后对剩余的服务列表按照RoundRobinRule策略进行访问。

(6)BestAvailableRule:优先选择并发请求最小的,刚启动时吗,如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够,才会切换回来。

(7)ZoneAvoidanceRule:可以实现避免可能访问失效的区域(zone) 

五、环境准备-搭建Eureka

1、建立Maven父工程

编写pom.xml

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>0.2.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--springCloud的依赖-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR12</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--SpringBoot-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.3.12.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

2、建立以下子工程

注:同样也是Maven。

3、配置springcloud-eureka-7001 

(1)目录如下

(2)导入依赖

<dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <!--导入Eureka Server依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--热部署工具-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

(3)编写配置文件

application.yml:

server:
  port: 7001
# Eureka配置
eureka:
  instance:
    # Eureka服务端的实例名字
    hostname: localhost
  client:
    # 表示是否向 Eureka 注册中心注册自己(这个模块本身是服务器,所以不需要)
    register-with-eureka: false
    # fetch-registry如果为false,则表示自己为注册中心,客户端的化为 ture
    fetch-registry: false
    # Eureka监控页面~
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

(4)编写启动器

注意:要在主启动器上方添加 @EnableEurekaServer表示 服务端的启动类,可以接受别人注册进来。

package com.yixin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaServer_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7001.class,args);
    }
}

4、配置springcloud-provider-blog-8001

(1)建立目录如下

(2)导入依赖

 <!--导包~-->
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <!--导入Eureka Server依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--Spring Boot-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
            <version>2.4.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.4.5</version>
        </dependency>
        <!--热部署工具-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

(3)编写配置文件

application.yml:

server:
  port: 8001
spring:
  application:
    name: springcloud-provider-blog
# Eureka配置:配置服务注册中心地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
  instance:
    instance-id: springcloud-provider-dept-8001 #修改Eureka上的默认描述信息

(4)编写BlogController

注:开发中,我们是需要连接到数据库的,但为了给大家演示清楚Ribbon,这里我们用简单dbsource来表示我们这个微服务对应的数据库。

package com.yixin.springcloud.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class BlogController {
    //表示db01这个数据库
    @Value("db01")
    private String dbsource;
    //注册进来的微服务,获取一些消息
    @GetMapping("/blog/info")
    public String discovery(){
        return dbsource;
    }
}

(5)编写启动类BlogProvider_8001

package com.yixin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class BlogProvider_8001 {
    public static void main(String[] args) {
        SpringApplication.run(BlogProvider_8001.class,args);
    }
}

5、编写springcloud-provider-blog-8002和springcloud-provider-blog-8003

(1)导入的依赖和springcloud-provider-blog-8001一样

(2) 配置springcloud-provider-blog-8002

a、application.yml(其实就是改了端口号而已)

server:
  port: 8002
spring:
  application:
    name: springcloud-provider-blog
# Eureka配置:配置服务注册中心地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
  instance:
    instance-id: springcloud-provider-dept-8002 #修改Eureka上的默认描述信息

b、编写BlogController

更改数据库名:db02

package com.yixin.springcloud.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class BlogController {

    //表示db02这个数据库
    @Value("db02")
    private String dbsource;
    //注册进来的微服务,获取一些消息
    @GetMapping("/blog/info")
    public String discovery(){
        return dbsource;
    }
}

c、编写启动类,和springcloud-provider-blog-8001一样

(3) 配置springcloud-provider-blog-8003

a、application.yml(其实就是改了端口号而已)

server:
  port: 8003
spring:
  application:
    name: springcloud-provider-blog
# Eureka配置:配置服务注册中心地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
  instance:
    instance-id: springcloud-provider-dept-8003 #修改Eureka上的默认描述信息

b、BlogController

更改数据库名:db03

package com.yixin.springcloud.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class BlogController {

    //表示db03这个数据库
    @Value("db03")
    private String dbsource;
    //注册进来的微服务,获取一些消息
    @GetMapping("/blog/info")
    public String discovery(){
        return dbsource;
    }
}

c、编写启动类,和springcloud-provider-blog-8001一样。

6、配置springcloud-consumer-blog-80

(1)目录如下

(2)导入依赖

 <!--导包~-->
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <!--导入Eureka依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--Spring Boot-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
            <version>2.4.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.4.5</version>
        </dependency>
        <!--热部署工具-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

(3)编写ConfigBean

package com.yixin.springcloud.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ConfigBean {

    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

(4)编写BlogConsumerController

package com.yixin.springcloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class BlogConsumerController {
    @Autowired
    private RestTemplate restTemplate;
    private static final String REST_URL_PREFIX="http://localhost:8001";
    @GetMapping("/consumer/blog")
    public String get(){
        return "消费端:"+restTemplate.getForObject(REST_URL_PREFIX +"/blog/info", String.class);
    }
}

(5)测试

依次启动:

  • springcloud-eureka-7001
  • springcloud-provider-blog-8002
  • springcloud-consumer-blog-80

访问:http://localhost:8000/consumer/blog

至此,Eureka就搭建好了!

六、集成Ribbon

6.1 搭建Ribbon

由于Ribbon属于进程式 LB(Load Balance),即将LB逻辑集成到消费方消费方从服务注册中心获知有哪些地址可用,所以我们只需要在消费方这边进行配置即可。

Eureka搭建好了,我们集成Ribbon非常简单,只需三步

配置springcloud-consumer-blog-80

(1)添加依赖:

   <!--Ribbon-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-ribbon</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>

(2)在配置类增加注解@LoadBalanced 

package com.yixin.springcloud.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ConfigBean {

    @LoadBalanced //配置负载均衡实现RestTemplate
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

(3)修改BlogConsumerController获取路径 

package com.yixin.springcloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class BlogConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    //private static final String REST_URL_PREFIX="http://localhost:8001";

    private static final String REST_URL_PREFIX="http://SPRINGCLOUD-PROVIDER-BLOG";

    @GetMapping("/consumer/blog")
    public String get(){
        return "消费端:"+restTemplate.getForObject(REST_URL_PREFIX +"/blog/info", String.class);
    }
}

注意:这里的SPRINGCLOUD-PROVIDER-BLOG指的就是我们服务注册中的服务名。

所以为了搭建服务产生方集群,我们刚刚在搭建springcloud-provider-blog-8001、springcloud-provider-blog-8002、springcloud-provider-blog-8003的时候,我们就已经将其服务名全部设置为一样的了。

至此,Ribbon就搭建好了,Ribbon的默认负载均衡算法轮询算法,也就是说,请求结束后都会向下一个服务端发送请求,例如 我们的有服务生产方A8001,服务端生产方B8002,服务端生产方C8003,那么消费端请求三次,依次的顺序是A,B,C。

我们来进行测试下:

  • 依次启动:
  • springcloud-eureka-7001
  • springcloud-provider-blog-8001
  • springcloud-provider-blog-8002
  • springcloud-provider-blog-8003
  • springcloud-consumer-blog-80

访问:http://localhost:7001/

可以发现,我们三个服务生产方已经成功绑定了。

接着重头戏来了!

进行测试:

访问:http://localhost:8000/consumer/blog

  • 访问第一次:

  • 访问第二次:

  • 访问第三次:

成功啦!!!

6.2  切换负载均衡的规则

修改springcloud-consumer-blog-80下的ConfigBean

package com.yixin.springcloud.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ConfigBean {

    @LoadBalanced //配置负载均衡实现RestTemplate
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

    /**
     * IRule:
     * RoundRobinRule 轮询策略
     * RandomRule 随机策略
     * AvailabilityFilteringRule : 会先过滤掉,跳闸,访问故障的服务~,对剩下的进行轮询~
     * RetryRule : 会先按照轮询获取服务~,如果服务获取失败,则会在指定的时间内进行,重试
     */
    @Bean
    public IRule myRule() {
        return new RandomRule();//使用随机策略
        //return new RoundRobinRule();//使用轮询策略
        //return new AvailabilityFilteringRule();//会先过滤掉,跳闸,访问故障的服务~,对剩下的进行轮询~
        //return new RetryRule();//会先按照轮询获取服务~,如果服务获取失败,则会在指定的时间内进行,重试
    }
}

测试:

重启springcloud-consumer-blog-80

访问:http://localhost:8000/consumer/blog

  • 访问第一次:

  • 访问第二次:

  • 访问第三次:

可以发现它是随机的!

6.3 自定义负载均衡的规则

在myRule包下自定义一个配置类MyRule.java。

注意:myRule包不要和主启动类所在的包同级。

(1)编写自定义规则MyRule

规则:每个服务访问5次,换下一个服务。

package com.yixin.myRule;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

@Configuration
public class MyRule extends AbstractLoadBalancerRule {
    // 每个服务访问 5 次,换下一个服务
    // total=0 => 默认 0,如果等于 5 ,指向下一个服务节点
    // index=0 => 默认 0,如果 total 等于 5 ,index+1
    private int total = 0; //被调用的次数
    private int currentIndex = 0; //当前谁在提供服务

    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;
        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            List<Server> upList = lb.getReachableServers(); //获得存活的服务
            List<Server> allList = lb.getAllServers();//获得全部服务
            int serverCount = allList.size();
            if (serverCount == 0) {
                /*
                 * No servers. End regardless of pass, because subsequent passes
                 * only get more restrictive.
                 */
                return null;
            }
// int index = chooseRandomInt(serverCount);//在区间内随机获得一个地址

// server = upList.get(index);//从存活的列表中获得
            //=================================
            total++;
            if (total > 5) {
                total = 0;
                currentIndex++;
            }
            if (currentIndex >= upList.size()) currentIndex = 0;
            server = upList.get(currentIndex);
            //=================================
            if (server == null) {
                /*
                 * The only time this should happen is if the server list were
                 * somehow trimmed. This is a transient condition. Retry after
                 * yielding.
                 */
                Thread.yield();
                continue;
            }
            if (server.isAlive()) {
                return (server);
            }
            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }
        return server;
    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        // TODO Auto-generated method stub
    }
}

(2)编写配置类MyRuleConf

作用:将我们写的这个规则注入到Spring中。

package com.yixin.myRule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyRuleConf {

    @Bean
    public IRule myRule(){
        return new MyRule();//自定义规则
    }
}

(3)启动类增加注解@RibbonClient

package com.yixin.springcloud;

import com.yixin.myRule.MyRuleConf;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

@SpringBootApplication
@EnableEurekaClient
//在微服务启动的时候就能加载自定义的Ribbon类(自定义的规则会覆盖原有默认的规则)
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-BLOG",configuration = MyRuleConf.class)//开启负载均衡,并指定自定义的规则
public class BlogConsumer_80 {

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

}

(4)测试

 重启 springcloud-consumer-blog-80

访问:http://localhost:8000/consumer/blog

  • 访问1-5次:

  • 访问第6-10次:

  • 访问第11-15次:

自定义规则测试成功!!!

总结

以上就是对基于Spring Cloud的负载均衡Ribbon知识点和实操的讲解,实现负载均衡可以将我们的压力分摊到多个操作单元。

这些仅为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • java导出大批量(百万以上)数据的excel文件

    java导出大批量(百万以上)数据的excel文件

    这篇文章主要为大家详细 介绍了java导出大批量即百万以上数据的excel文件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • java数据结构与算法之简单选择排序详解

    java数据结构与算法之简单选择排序详解

    这篇文章主要介绍了java数据结构与算法之简单选择排序,结合实例形式分析了选择排序的原理、实现方法与相关操作技巧,需要的朋友可以参考下
    2017-05-05
  • Springboot pom项目间接依赖包版本与预期不符原因解决分析

    Springboot pom项目间接依赖包版本与预期不符原因解决分析

    这篇文章主要介绍了Springboot pom项目间接依赖包版本与预期不符原因解决分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • Java编程代码性能优化

    Java编程代码性能优化

    本文介绍了 Java 代码优化的过程,总结了优化 Java 程序的一些最佳实践,分析了进行优化的方法,并解释了性能提升的原因,需要的朋友可以参考下
    2015-11-11
  • Springboot+mybatis plus找不到mapper.xml的问题解决

    Springboot+mybatis plus找不到mapper.xml的问题解决

    本文主要介绍了Springboot+mybatis plus找不到mapper.xml的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • Spring整合Mybatis思路梳理总结

    Spring整合Mybatis思路梳理总结

    mybatis-plus是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生,下面这篇文章主要给大家介绍了关于SpringBoot整合Mybatis-plus案例及用法实例的相关资料,需要的朋友可以参考下
    2022-12-12
  • MyBatis框架零基础快速入门案例详解

    MyBatis框架零基础快速入门案例详解

    MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架
    2022-04-04
  • 解决RestTemplate反序列化嵌套对象的问题

    解决RestTemplate反序列化嵌套对象的问题

    这篇文章主要介绍了解决RestTemplate反序列化嵌套对象的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • Java继承与多态的正确打开方式

    Java继承与多态的正确打开方式

    这篇文章主要为大家介绍了Java的继承与多态,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • SpringBoot实现动态定时任务

    SpringBoot实现动态定时任务

    这篇文章主要为大家详细介绍了SpringBoot实现动态定时任务,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-04-04

最新评论