SpringBoot中使用ThreadPoolExecutor和ThreadPoolTaskExecutor线程池的方法和区别

Java线程池的拒绝策略 拒绝策略被设置为CallerRunsPolicy,即当任务被拒绝时,由提交任务的线程来执行该任务。这是线程池默认的拒绝策略。在这个示例中,我们创建了一个线程池,并设置核心线程数为2,最大线程数为4,使用有界队列(大小为3)。DiscardOldestPolicy:当任务被拒绝时,丢弃队列中最老的一个任务,并尝试再次提交被拒绝的任务。,这意味着当线程池无法处理新的任务时,会丢弃队列中的最早的任务,并尝试将新的任务添加到队列中。,这意味着当线程池无法处理新的任务时,会默默地丢弃被拒绝的任务,不抛出任何异常。 阅读详情

        Java中经常用到多线程来处理业务。在多线程的使用中,非常的不建议使用单纯的Thread或者实现Runnable接口的方式来创建线程,因为这样的线程创建及销毁势必会造成耗费资源、线程上下文切换问题,同时创建过多的线程也可能会引发资源耗尽的风险,对线程的管理非常的不方便。因此在使用多线程的时候,日常开发中我们经常引入的是线程池,利用线程池十分方便的对线程任务进行管理。

        这里主要对线程池ThreadPoolExecutor和ThreadPoolTaskExecutor进行对比与使用见解。

一、ThreadPoolExecutor

该图是它的继承关系

 它的构造方法为

public ThreadPoolExecutor(int coreSize,
        int maxSize,
        long keepAliveTime,
        TimeUnit unit,
        BlockingQueue<Runnable> workQueue,
        ThreadFactory threadFactory,
        RejectedExectionHandler handler);

几个参数的含义分别是:

coreSize:核心线程数,也是线程池中常驻的线程数
maxSize:最大线程数,在核心线程数的基础上可能会额外增加一些非核心线程,需要注意的是只有当workQueue队列填满时才会创建多于核心线程数的线程
keepAliveTime:非核心线程的空闲时间超过keepAliveTime就会被自动终止回收掉
unit:keepAliveTime的时间单位
workQueue:用于保存任务的队列,可以为直接提交队列、无界任务队列、有界任务队列、优先任务队列类型之一,当池子里的工作线程数大于核心线程数时,这时新进来的任务会被放到队列中
threadFactory:执行程序创建新线程时使用的工厂
handler:线程池无法继续接收任务是的拒绝策略

workQueue任务队列

        workQueue任务队列可以为直接提交队列、无界任务队列、有界任务队列、优先任务队列类型之一,示例如下

例1:直接提交队列

SynchronousQueue它没有容量,每执行一个插入操作就会阻塞,需要再执行一个删除操作才会被唤醒,反之每一个删除操作也都要等待对应的插入操作

        当创建的线程数大于最大线程数时,会直接执行设置好的拒绝策略

new ThreadPoolExecutor(1,
        2,
        1000,
        TimeUnit.MILLISECONDS,
        new SynchronousQueue<Runnable>(),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.AbortPolicy()
    );

例2:有界的任务队列

ArrayBlockingQueue有界的任务队列。如果有新的任务需要执行时,线程池会创建新的线程,知道创建的线程数量达到核心线程数时,则会将新的任务加入到等待的队列中。如果等待的队列已满,则会继续创建线程,直到线程数量达到设定的最大线程数,如果创建的线程数大于了最大线程数,则执行拒绝策略。

new ThreadPoolExecutor(
        1, 
        2, 
        1000, 
        TimeUnit.MILLISECONDS, 
        new ArrayBlockingQueue<Runnable>(10), 
        Executors.defaultThreadFactory(), 
        new ThreadPoolExecutor.AbortPolicy()
    );

 例3:无界的任务队列

LinkedBlockingQueue无界的任务队列,线程池的任务队列可以无限制的添加新的任务,而线程池创建的最大线程数就是设定的核心线程数量,也就是说在这种情况下,就算你设置了最大线程数也是无效的,哪怕你的任务队列中缓存了很多未执行的任务,当线程池的线程数达到corePoolSize后,就不会再增加了;若后续有新的任务加入,则直接进入队列等待,当使用这种任务队列模式时,一定要注意你任务提交与处理之间的协调与控制,不然会出现队列中的任务由于无法及时处理导致一直增长,直到最后资源耗尽的问题。

new ThreadPoolExecutor(
        1, 
        2, 
        1000, 
        TimeUnit.MILLISECONDS, 
        new LinkedBlockingQueue<Runnable>(),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.AbortPolicy()
    );

 例4:优先任务队列

        PriorityBlockingQueue优先任务队列,线程池的线程数一直为设定的核心线程数个,无论添加多少个任务,线程池创建的线程数也不会超过你设定的核心线程数,只不过PriorityBlockingQueue队列内的任务可以自定义队则根据任务的优先级顺序进行执行,不同于其它队列是按照先进先出的规则处理的

new ThreadPoolExecutor(1,
        2,
        1000,
        TimeUnit.MILLISECONDS,
        new PriorityBlockingQueue<Runnable>(),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.AbortPolicy()
    );

线程池拒绝策略

AbortPolicy

       直接抛出异常阻止系统正常工作

CallerRunsPolicy

       只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务

DiscardOldestPolicy

       丢弃最老的一个请求,尝试再次提交当前任务

DiscardPolicy

       丢弃无法处理的任务,不给予任何处理

除上述拒绝策略外,可以实现RejectedExecutionHandler接口,自定义拒绝策略

new ThreadPoolExecutor(
                1,
                2,
                1000,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(5),
                Executors.defaultThreadFactory(),
                new RejectedExecutionHandler() {
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor)                             
                    {
                        System.out.println(r.toString() + "执行了拒绝策略");
                    }
                });

ThreadPoolExecutor工作流程

        当一个新的任务提交给线程池时,线程池的处理步奏:

1、首先判断核心线程数是否已满,如果没满则调用一个线程处理Task任务,如果已满则执行步奏2;

2、这时会判断阻塞队列是否已满,如果阻塞队列没满,就将Task任务加入到阻塞队列中等待执行,如果阻塞队列已满,则执行步奏3;

3、判断是否大于最大线程数,如果小于最大线程数,则创建线程执行Task任务,如果大于最大线程数,则执行步骤4;

4、这时会使用淘汰策略来处理无法执行的Task任务

ThreadpoolExecutor线程池的使用

书写一个配置类,在配置类中定义一个bean,如下

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


@Configuration
@Slf4j
@EnableAsync
public class ExecutorConfig {

    @Bean
    public ThreadPoolExecutor asyncExecutor(){
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                10,
                20,
                1000,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(5),
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        System.out.println("线程"+r.hashCode()+"创建");
                        //线程命名
                        Thread th = new Thread(r,"threadPool"+r.hashCode());
                        return th;
                    }
                },
                new ThreadPoolExecutor.CallerRunsPolicy()
        ){
            @Override
            protected void beforeExecute(Thread t, Runnable r) {
                System.out.println("准备执行:"+ ((ThreadTask)r).getTaskName());
                super.beforeExecute(t, r);
            }

            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                System.out.println("执行完毕:"+((ThreadTask)r).getTaskName());
                super.afterExecute(r, t);
            }

            @Override
            protected void terminated() {
                System.out.println("线程池退出");
                super.terminated();
            }
        };
        return executor;
    }

}

说明:

  1. beforeExecute:线程池中任务运行前执行
  2. afterExecute:线程池中任务运行完毕后执行
  3. terminated:线程池退出后执行

代码中的ThreadTask如下,此处可根据自己需求进行代码编写

public class ThreadTask implements Runnable {

    private String taskName;

    public String getTaskName() {
        return taskName;
    }

    public void setTaskName(String taskName) {
        this.taskName = taskName;
    }

    public ThreadTask(String name) {
        this.setTaskName(name);
    }

    public void run() {
        //输出执行线程的名称
        System.out.println("TaskName"+this.getTaskName()+"---ThreadName:"+Thread.currentThread().getName());
    }
}

二、ThreadPoolTaskExecutor

ThreadPoolTaskExecutor这个类是Spring-Context支持的一个,专门用于Spring环境的线程池。其底层是在ThreadPoolExecutor的基础上包装的一层,使得Spring的整合更加方便

继承关系如下

 其成员变量如ThreadPoolExecutor,有核心线程数、最大线程数、keepAliveTIme、超时时间单位、队列、线程创建工厂、拒绝策略

查看它的源码如下

 

 可以看出,它依赖的还是ThreadPoolExecutor,并且注意它直接设定了keepAliveTime的时间单位

它的队列、拒绝策略通ThreadPoolExecutor一致

ThreadPoolTaskExecutor的使用

书写一个配置类,在配置类中对线程池ThreadPoolTaskExecutor进行配置

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;


@Configuration
@Slf4j
@EnableAsync
public class ExecutorConfig {

    @Bean
    public ThreadPoolTaskExecutor asyncExecutor() {
        log.info("start asyncServiceExecutor");
        ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(10);
        //配置最大线程数
        executor.setMaxPoolSize(20);
        //配置队列大小
        executor.setQueueCapacity(100);
        //配置keepAliveTime
        executor.setKeepAliveSeconds(10);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("async-service-");
        //拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }

}

配置类中的VisiableThreadPoolTaskExecutor()类扩展了ThreadPoolTaskExecutor,对线程执行前后各阶段做了补充操作,类似于上面ThreadPoolExecutor中的beforeExecute、afterExecute等操作,具体代码如下

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;

@Slf4j
public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {

    private void showThreadPoolInfo(String prefix) {
        ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();

        if (null == threadPoolExecutor) {
            return;
        }

        log.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",
                this.getThreadNamePrefix(),
                prefix,
                threadPoolExecutor.getTaskCount(),
                threadPoolExecutor.getCompletedTaskCount(),
                threadPoolExecutor.getActiveCount(),
                threadPoolExecutor.getQueue().size());
    }

    @Override
    public void execute(Runnable task) {
        showThreadPoolInfo("1. do execute");
        super.execute(task);
    }

    @Override
    public void execute(Runnable task, long startTimeout) {
        showThreadPoolInfo("2. do execute");
        super.execute(task, startTimeout);
    }

    @Override
    public Future<?> submit(Runnable task) {
        showThreadPoolInfo("1. do submit");
        return super.submit(task);
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        showThreadPoolInfo("2. do submit");
        return super.submit(task);
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        showThreadPoolInfo("1. do submitListenable");
        return super.submitListenable(task);
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        showThreadPoolInfo("2. do submitListenable");
        return super.submitListenable(task);
    }
}

三、线程池在接口中的具体使用

 上述描述中,最终书写了一个配置类,对线程池进行了配置,定义了一个bean对象,那么在具体接口中该怎么使用,如下所示

1、创建controller层,书写接口入口,调用server层代码

import com.smile.syncproject.service.AsyncService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("async")
@Slf4j
public class AsyncController {

    @Autowired
    private AsyncService asyncService;

    @RequestMapping("test")
    public String test() {
        log.info("start submit");

        //调用service层的任务
        asyncService.executeAsync();

        log.info("end submit");

        return "success";
    }

}

 2、在service层实现层进行线程池的使用

        通过注解@Async

@Async("asyncServiceExecutor")

注解内的值就是上面定义好的配置类中的bean的名称。如果有多个线程池,就需要在定义不同bean的时候指定其name了

import com.smile.syncproject.service.AsyncService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class AsyncServiceImpl implements AsyncService {

    @Override
    @Async("asyncServiceExecutor")
    public void executeAsync() {
        log.info("start executeAsync");
        try{
            Thread.sleep(1000);
        }catch(Exception e){
            e.printStackTrace();
        }
        log.info("end executeAsync");
    }

}

四、其它

1、线程池大小的设置

        针对这个问题,我们首先要确认的是我们的需求是计算密集型还是IO密集型。

        如果是计算密集型,比较理想的方案是:线程数 = CPU核数 + 1,也可以设置成CPU核数*2,一般设置CPU*2

        如果是IO密集型,线程数 = CPU核心数/(1-阻塞系数),这个组赛系数一般为0.8~0.9之间,也可以取0.8或者0.9.

Netty线程模型(Netty的高性能原理探秘) 缘起 日前在看netty的工作原理,对netty的线程模型很是不能理解,查阅了诸多资料,终于有了一些眉目。特此记录,已被查阅。 阅读对象 netty是基于java Nio的封装,所以需要读者对java NIO有一定的了解,篇幅所限,本文不会对NIO再做详述,有需要的读者可以查看JAVA BIO,NIO,AIO详解(附代码实现)以及Netty的简介 Netty的线程模型 说netty的线程模型之前,... 阅读详情

相关推荐

Spring Boot(六十七):多线程ThreadPoolTaskExecutor使用

到了springboot这里,因为引入了spring-boot-autoconfigurer,自动装配机制,在task包下,直接把ThreadPoolTaskExecutor注入到bean容器里面。所以在springboot项目中,如果要使用线程池,可以直接使用,都不用额外任何配置。在spring框架中,spring提供了ThreadPoolTaskExecutor来创建线程池,该类在spring-context包下。扩展ThreadPoolTaskExecutor类。

u013938578的博客 904

springboot之线程池ThreadPoolTaskExecutor以及@Async异步注解

前言 最近项目当中有需求,要进行异步的处理,需要使用到线程池,很久没有使用到线程池了,一来是做JAVAweb开发基本上很少用到异步处理,二来是发现有的老项目里面,线程和线程池的使用比较混乱,有好几个线程池,有的线程池是通过spring管理的,有的是自己创建的,然后有的地方是直接创建的线程。所以这里记录下自己在项目当中如何优雅的使用线程池!避免项目当中到处都是线程池!!! SpringBoot整合ThreadPoolTaskExecutor线程池 ThreadPoolExecut...

zzhongcy的专栏 6349

SpringBoot整合ThreadPoolTaskExecutor实现线程池异步多任务

SpringBoot整合ThreadPoolTaskExecutor实现线程池异步多任务

Jaemon 3734

springboot自帶线程池ThreadPoolTaskExecutor使用

spring提供的线程池ThreadPoolTaskExecutor使用以及需要注意的问题,修改配置是为了避免oom风险,设置线程池是为了降低并发场景下线程创建销毁开销等问题。

feinifi的博客 7415

《联邦学习实战》杨强 读书笔记十四——构建公平的大数据交易市场

当数据具有资产属性之后,数据便可以直接或者间接地为公司、为社会创造价值和收益,并且可以作为一种特殊的商品在市场中进行交易。 与传统的商品交易相比,数据资产交易的市场前景更广阔,但同时也面临着很多的挑战,主要包括: 数据的质量、价格如何定义 在合法合规的前提下,数据的交易如何确保不会泄露用户的隐私 如何构建合理的激励机制来鼓励更多的参与方加入数据交易市场中 大数据交易 数据交易的定义 数据交易是指一种对数据进行买卖的行为,大数据交易由三方共同参与,分别为数据提供方、大数据交易平台和数据需求方:

IEEE802_11的博客 3433

linux入侵排查-综合日志分析

2.分析攻击者首次成功登录web管理后台的时间 还可以知道攻击者可能是通过10.2.4.11这个跳板服务器跳过来的,然后我们继续排查,可以发现日志中POST请求大多都是1047字节,然后往后大多是300字节,POST请求的响应状态码有200和302这两个,其中的302是爆破成功后持续爆破产生的日志,再1047字节和300字节中间夹着一个978字节,就是200响应和302响应的中间。7.分析攻击者留下的持久化后门的时间和后门执行情况 排查计划任务,发现有一个计划任务还是被加密的,应该是反弹shell的。

chinese_cabbage0的博客 643

Springboot项目中线程池使用整理

Spring环境:优先使用@Bean配置ThreadPoolTaskExecutor全局异步配置:实现AsyncConfigurer接口特殊性能要求:使用private static final方式。

m0_74823239的博客 858

【超详细】基于YOLOv8的PCB缺陷检测

印刷电路板(PCB)瑕疵数据集:是一个公共的合成PCB数据集,由北京大学发布,其中包含1386张图像以及6种缺陷(缺失孔,鼠标咬伤,开路,短路,杂散,伪铜),用于检测,分类和配准任务。本文我们选取了其中适用与检测任务的693张图像,随机选择593张图像作为训练集,100张图像作为验证集。

weixin_45679938的博客 2万+

springboot 多线程实现

有时候,,如果,系统就要,有时会。而且当线程数量太多时,

m0_67393295的博客 2468

LangChain与LangGraph核心区别解析

LangChain与LangGraph是当前大语言模型(LLM)应用开发中两个紧密相关且极具影响力的开源框架。它们源于LangChain AI公司,设计哲学互补,旨在解决不同维度的LLM工程化问题,共同构成了构建复杂智能应用的强大工具集。

weixin_35774598的博客 1908

全面解析 SAP 事务码 LTMOM 的应用与实践

综上所述,事务码 LTMOM 是 SAP 系统中不可或缺的迁移对象维护工具,它不仅提供了对数据迁移对象的精细配置功能,还通过灵活的数据转换规则与异常监控机制,为企业数据从 SAP ERP 向 SAP S/4HANA 的迁移提供了坚实保障。在数据迁移过程中,并非所有的迁移对象都需要同时启用。业内专家普遍认为,未来的系统升级与数据迁移将更注重业务需求的动态变化与数据实时性的要求,而 LTMOM 作为核心工具,其在流程自动化、数据智能校验以及跨系统数据联动方面的能力,将直接影响企业整体数字化转型的成败。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1004

Java线程池和SpringBoot异步线程池

目录 一、SpringBoot异步线程池 1、定义线程池 2、线程池的使用 二、ThreadPoolTaskExecutor和ThreadPoolExecutor区别 1、ThreadPoolExecutor的处理流程  2、四种Reject预定义策略 三、Java线程池 1、使用线程池的优势 2、什么是阻塞队列? 3、线程池为什么要是使用阻塞队列? 4、如何配置线程池? ...

swadian2008的博客 2340

Linux安装Docker(图文解说详细版)

第一步,下载docker 下载地址: https://download.docker.com/linux/static/stable/x86_64/ 这次的演示我们使用docker-18.06.3-ce.tgz 这个版本 第二步,上传到云服务器上面 使用rz命令上传或者fltp工具进行上传 第三步,解压文件 第四步,将解压出来的docker文件复制到 /usr/bin/ 目录下 这么做的目的是将docker交给linux自己去管理,类似spring中的ioc(猜测,非正经知识) cp docker

编码人生 1万+

springboot配置多个线程池

springboot配置多个线程池

_紫陌纤尘的博客 1万+

ImportError: DLL load failed while importing _pydantic_core: 找不到指定的程序对应解决方案

本文主要介绍了ImportError: DLL load failed while importing _pydantic_core: 找不到指定的程序对应解决方案,希望能对使用Python的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 19万+

Open3D 进阶(32)渐进三角网(PTD)地面滤波

渐进三角网地面滤波算法(Progressive TIN Densification, PTD)是一种广泛应用于机载LiDAR点云数据处理的滤波方法,旨在从复杂场景中精确分离地面点,以生成数字高程模型(DEM)。

点云侠的博客 1537

Spring boot中的线程池-ThreadPoolTaskExecutor

讲解都在B站里面

ws_please的博客 1528

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

spring线程池ThreadPoolTaskExecutor与阻塞队列BlockingQueue

一:  ThreadPoolTaskExecutor是一个spring的线程池技术,查看代码可以看到这样一个字段: private ThreadPoolExecutor threadPoolExecutor;   可以发现,spring的 ThreadPoolTaskExecutor是使用的jdk中的java.util.concurrent.ThreadPoolExecuto...

weixin_34067102的博客 1027

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

02-Java SE-线程池和SpringBoot异步线程池

Java线程池和SpringBoot异步线程池 地址: https://blog.youkuaiyun.com/swadian2008/article/details/105558562?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161465137516780269862342%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_

liumangtutu2919的博客 477

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

SpringBoot用线程池ThreadPoolExecutor处理百万级数据

ThreadPoolTaskExecutor和ThreadPoolExecutor比Executors创建线程池更加灵活,可以设置参数,推荐ThreadPoolTaskExecutor和ThreadPoolExecutor,而ThreadPoolTaskExecutor是ThreadPoolExecutor的封装,所以,性能更加优秀,如:kettle、ES、redis\mongoDB、springboot、Zookeeper、高并发多线程、中间件、JVM、程序员攻略等。推荐大家关注一个公众号。

竹林幽深 340

【线程池】springboot线程池的底层设计原理

在 Spring Boot 中,线程池是一个重要的组件,用于管理和调度线程,提高应用程序的性能和资源利用率。下面将详细汇总 Spring Boot 线程池的底层原理。

weixin_44823875的博客 1044

【JUC】SpringBoot使用线程池的两种方式 注解和注入

【JUC】SpringBoot使用线程池的两种方式 注解和注入

lushixuan12345的博客 2842
上一篇: SpringBoot中使用本地缓存
下一篇: 通过gateway调用其它服务时503问题
one_smail
博客等级 码龄9年 175粉丝 179原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

one_smail

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值