锋盈数科-知识库 Logo
首页
软件开发
计算机基础
Hello Halo
新手必读
关于本知识库
登录 →
锋盈数科-知识库 Logo
首页 软件开发 计算机基础 Hello Halo 新手必读 关于本知识库
登录
  1. 首页
  2. 软件开发
  3. 【SpringBoot整合系列】SpringBoot整合定时任务【Quartz】

【SpringBoot整合系列】SpringBoot整合定时任务【Quartz】

0
  • 软件开发
  • 发布于 2024-08-17
  • 0 次阅读
黄健
黄健

layout: post
title: 【SpringBoot整合系列】SpringBoot整合定时任务【Quartz】
date: 24-04-01 21:51:09 修改
author: 'zhangtao'
header-img: 'img/post-bg-2015.jpg'
catalog: false
tags:

  • Java
  • SpringBoot
  • spring boot
  • 后端
  • java


目录

  • 关于定时任务
    • 相关名词
  • java 定时任务调度的实现方式
    • 1.Timer
      • Java原生实现
    • 2.ScheduledExecutor
    • 3.Spring Scheduler
    • 4.开源工具包 JCronTab
    • 5.开源工具包 <font color=#900>Quartz</font >
  • Quartz
    • Quartz的相关概念
    • 特点
    • Quartz的一些使用场景
  • Quartz框架中MisFire的理解
    • MisFire
      • Misfire主要定义了五种常量:
    • Quartz常常由于下列几种情况导致任务的MisFire:
    • 分析
      • 如何判定一个任务是MissFire
      • 判定一个任务为MissFire后,Quartz的补偿机制区别
        • withMisfireHandlingInstructionDoNothing
        • withMisfireHandlingInstructionIgnoreMisfires
        • withMisfireHandlingInstructionFireAndProceed(默认)
      • 案例:三种执行策略详解:
  • springboot整合Quartz
    • 1.引入依赖
    • 2.ScheduleConstants常量类
    • 3.SysJob实体类
    • 4.SpringUtils工具类
    • 5.核心配置类
      • 先简单梳理一些每个实体类的大致作用,以及它们之间的联系和执行逻辑。
      • 执行逻辑:
      • 5.1 JobExecuteUtils执行定时任务方法类
      • 5.2 AbstractQuartzJob抽象类
      • 5.3 QuartzJobExecution/QuartzDisallowConcurrentExecution开启/禁止并发执行任务类
        • 允许并发执行:
        • 不允许并发执行(@DisallowConcurrentExecution):
      • 5.4 ScheduleUtils定时任务工具类
        • getQuartzJobClass
        • handleCronScheduleMisfirePolicy
        • createScheduleJob
        • 代码
      • 5.5 SysJobService定时任务调度信息接口
      • 5.6 SysJobServiceImpl定时任务调度信息接口实现类
    • 测试一下吧
      • 任务一:
      • 任务二:

{#_1}关于定时任务

{#1_126}1.引入依赖

SpringBoot版本:2.7.16

				<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--quartz依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter-test</artifactId>
            <version>3.0.3</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>

        <!--常用工具类 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

{#2ScheduleConstants_169}2.ScheduleConstants常量类

package com.zjl.constant;

/**
 * @author: zjl
 * @datetime: 2024/4/1
 * @desc: Misfire定义的五种常量
 */
public class ScheduleConstants {
   
    //参数
    public static final String TASK_PARAMS = "PARAMS";
    //默认
    public static final String MISFIRE_DEFAULT = "0";
    //忽略错过的执行,按新 Cron 继续运行。
    public static final String MISFIRE_IGNORE_MISFIRES = "1";
    //补偿错过的执行,然后继续运行。
    public static final String MISFIRE_FIRE_AND_PROCEED = "2";
    //错过的执行不做任何处理,等待下一次 Cron 触发。
    public static final String MISFIRE_DO_NOTHING = "3";
}

{#3SysJob_192}3.SysJob实体类

这边我只列举了一些必须会用到的字段,其他字段可以根据实际需求来进行扩展。

package com.zjl.domain;

import lombok.Data;
import com.zjl.constant.ScheduleConstants;

/**
 * @author: zjl
 * @datetime: 2024/4/1
 * @desc:
 */
@Data
public class SysJob {
   
    //定时任务ID
    private String jobId;
    //定时任务名称
    private String jobName;
    //定时任务组
    private String jobGroup;
    //目标bean名
    private String beanTarget;
    //目标bean的方法名
    private String beanMethodTarget;
    //执行表达式
    private String cronExpression;
    //是否并发 0:代表允许并发执行 1:代表不允许并发执行
    private String concurrent;
    //计划策略
    private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT;
}

{#4SpringUtils_226}4.SpringUtils工具类

  1. 实现BeanFactoryPostProcessor接口,重写postProcessBeanFactory()方法,在所有Bean初始化之前就会被执行,因此可以在此处获取到最主要的BeanFactory。
  2. 通过beanFactory对象提供的API实现获取 Bean功能
package com.zjl.utils;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

/**
 * @author: zjl
 * @datetime: 2024/4/1
 * @desc:
 */
@Component
public final class SpringUtils implements BeanFactoryPostProcessor {
   
    //Spring应用上下文环境
    private static ConfigurableListableBeanFactory beanFactory;
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
   
        SpringUtils.beanFactory = beanFactory;
    }
    /**
     * 获取对象
     * @param name
     * @return Object 一个以所给名字注册的bean的实例
     * @throws BeansException
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) throws BeansException {
   
        return (T) beanFactory.getBean(name);
    }
}

{#5_263}5.核心配置类

{#_264}先简单梳理一些每个实体类的大致作用,以及它们之间的联系和执行逻辑。

| 实体类类 | 作用 |
|:---|
| JobExecuteUtils | 任务执行的工具类,通过反射调用目标Bean的方法。 |
| AbstractQuartzJob | 抽象QuartzJob类,实现了execute方法,在执行任务前后做了trycatch。 |
| QuartzJobExecution | 任务执行类,继承AbstractQuartzJob,在doExecute方法中调用JobExecuteUtils、executeMethod执行目标方法。 |
| QuartzDisallowConcurrentExecution | 禁止并发执行的任务执行类,也继承自AbstractQuartzJob,执行逻辑同QuartzJobExecution。 |
| ScheduleUtils | 任务调度的工具类,根据SysJob创建JobDetail和CronTrigger,调度任务。 |
| SysJobService | 任务管理业务接口,定义了初始化、增加、修改、删除任务等方法。 |
| SysJobServiceImpl | 任务管理业务接口实现类。 |

{#_275}执行逻辑:

  1. 初始化时,SysJobServiceImpl从数据库加载定时任务,调度到调度器。
  2. 调度器根据CronTrigger触发时间启动JobDetail。
  3. JobDetail执行时调用对应Job类的execute方法。
  4. AbstractQuartzJob实现了execute方法,在其中调用子类doExecute。
  5. 子类QuartzJobExecution的doExecute通过JobExecuteUtils反射执行目标方法。
  6. 这样就完成了定时任务的执行。

{#51_JobExecuteUtils_282}5.1 JobExecuteUtils执行定时任务方法类

  1. 我们通过jobExecutionContext.getMergedJobDataMap().get(TASK_PARAMS);这个方法去获取咱们的SysJob参数信息。
  2. 默认获取的是Object类型,所以我们需要通过BeanUtils.copyProperties(param,sysJob);这个方法进行实体类的转换和拷贝,注意参数顺序别写反了。
  3. 然后我们通过SpringUtils封装好的getBean方法,通过拷贝好的实体类中的参数去动态进行获取被Spring托管的Bean。
  4. 获取到Bean之后通过bean.getClass().getMethod(sysJob.getBeanMethodTarget());这个代码去获取Bean中需要执行的方法。
  5. 最后通过method.invoke(bean);进行执行Bean中对应的方法内容。
package com.zjl.utils;

import com.zjl.domain.SysJob;
import org.quartz.JobExecutionContext;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static com.zjl.constant.ScheduleConstants.TASK_PARAMS;

/**
 * @author: zjl
 * @datetime: 2024/4/1
 * @desc:
 */
public class JobExecuteUtils {
   
    /**
     * 获取bean并执行对应的方法
     * @param jobExecutionContext
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void executeMethod(JobExecutionContext jobExecutionContext) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
   
        Object param = jobExecutionContext.getMergedJobDataMap().get(TASK_PARAMS);
        SysJob sysJob = new SysJob();
        BeanUtils.copyProperties(param,sysJob);
        Object bean = SpringUtils.getBean(sysJob.getBeanTarget());
        Method method = bean.getClass().getMethod(sysJob.getBeanMethodTarget());
        method.invoke(bean);
    }
}

{#52_AbstractQuartzJob_324}5.2 AbstractQuartzJob抽象类

定义了一个抽象类并实现了Job接口,同时重写execute方法。这个方法是定时任务执行的核心方法,其次在这个抽象类当中我们还定义了一个doExecute方法,主要就是为了写我们定时任务的执行逻辑。

package com.zjl.domain;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.lang.reflect.InvocationTargetException;

/**
 * @author: zjl
 * @datetime: 2024/4/1
 * @desc: 抽象类 Quartz调用
 */
public abstract class AbstractQuartzJob implements Job {
   
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
   
        try {
   
            doExecute(jobExecutionContext);
        } catch (Exception e) {
   
            throw new RuntimeException(e);
        }
    }
    protected abstract void doExecute(JobExecutionContext jobExecutionContext) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException;
}

{#53_QuartzJobExecutionQuartzDisallowConcurrentExecution_353}5.3 QuartzJobExecution/QuartzDisallowConcurrentExecution开启/禁止并发执行任务类

继承上述的抽象类,通过@DisallowConcurrentExecution这个注解来禁止咱们的定时任务的并发执行,如果不加则是默认允许并发执行,最后我们重写了doExecute方法去执行我们定时任务的处理逻辑。
例如有个定时任务每隔5秒执行一次,不过这个任务做完可能需要20秒。

{#_356}允许并发执行:

在这处理的20秒钟,肯定需要处理下一个任务了,如果设置了允许并发执行,不会等到上一个任务执行完毕才会执行下一个任务,只要每隔5s就会执行下一个任务。

package com.zjl.domain;

import org.quartz.JobExecutionContext;
import java.lang.reflect.InvocationTargetException;
import static com.zjl.utils.JobExecuteUtils.executeMethod;

/**
 * @author: zjl
 * @datetime: 2024/4/1
 * @desc:
 */
public class QuartzJobExecution extends AbstractQuartzJob {
   
    @Override
    protected void doExecute(JobExecutionContext jobExecutionContext) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
   
        executeMethod(jobExecutionContext);
    }
}

允许并发执行体现在任务一中

{#DisallowConcurrentExecution_379}不允许并发执行(@DisallowConcurrentExecution):

在这处理的20秒钟,肯定需要处理下一个任务了,如果设置了不允许并发执行,会必须等到上一个任务执行完毕才会执行下一个任务

package com.zjl.domain;

import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import java.lang.reflect.InvocationTargetException;
import static com.zjl.utils.JobExecuteUtils.executeMethod;

/**
 * @author: zjl
 * @datetime: 2024/4/1
 * @desc: 定时任务处理(禁止并发执行)
 */
@DisallowConcurrentExecution
public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob
{
   
    @Override
    protected void doExecute(JobExecutionContext jobExecutionContext) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
   
        executeMethod(jobExecutionContext);
    }
}

不允许并发执行体现在任务二中

{#54_ScheduleUtils_406}5.4 ScheduleUtils定时任务工具类

一共封装三个方法

{#getQuartzJobClass_408}getQuartzJobClass

这个方法是主要通过SysJob实体类当中会通过动态参数获取任务类并决定当前任务是否并发执行(0代表并发执行,1代表禁止并发执行)

{#handleCronScheduleMisfirePolicy_410}handleCronScheduleMisfirePolicy

这个方法主要设置待执行任务的执行策略。

{#createScheduleJob_412}createScheduleJob

这个方法是最主要的方法,它的逻辑总共7个步骤如下:

  1. 得到任务类(是否并发执行)
  2. 构建job信息
  3. 构件表达式调度构建器
  4. 配置执行策略
  5. 按新的cronExpression表达式构建一个新的trigger
  6. 放入参数,运行时的方法可以获取
  7. 执行调度任务
{#_421}代码
package com.zjl.utils;

import com.zjl.constant.ScheduleConstants;
import com.zjl.domain.QuartzDisallowConcurrentExecution;
import com.zjl.domain.QuartzJobExecution;
import com.zjl.domain.SysJob;
import org.quartz.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.InvocationTargetException;

import static com.zjl.constant.ScheduleConstants.TASK_PARAMS;

/**
 * @author: zjl
 * @datetime: 2024/4/1
 * @desc: 定时任务工具类
 */
@Component
public class ScheduleUtils {
   
    /**
     * 得到quartz任务类
     * @param sysJob 执行计划
     * @return 具体执行任务类
     */
    private static Class<? extends Job> getQuartzJobClass(SysJob sysJob) {
   
        boolean isConcurrent = "0".equals(sysJob.getConcurrent());
        return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
    }
    /**
     * 创建定时任务
     */
    public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
   
        //获取任务类型
        Class<? extends Job> jobClass = getQuartzJobClass(job);
        // 构建job信息
        String cornExpression = job.getCronExpression();
        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(job.getJobId(),job.getJobGroup()).build();
        // 表达式调度构建器
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cornExpression);
        //配置执行策略
        cronScheduleBuilder = handleCronScheduleMisfirePolicy(job,cronScheduleBuilder);
        // 按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobId(),job.getJobGroup())
                .withSchedule(cronScheduleBuilder).build();
        // 放入参数,运行时的方法可以获取
        jobDetail.getJobDataMap().put(TASK_PARAMS, job);
        // 执行调度任务
        scheduler.scheduleJob(jobDetail, trigger);
    }
    /**
     * 设置定时任务策略
     */
    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb) {
   
        switch (job.getMisfirePolicy()) {
   
            case ScheduleConstants.MISFIRE_DEFAULT:
                return cb;
            case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
                return cb.withMisfireHandlingInstructionIgnoreMisfires();
            case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
                return cb.withMisfireHandlingInstructionFireAndProceed();
            case ScheduleConstants.MISFIRE_DO_NOTHING:
                return cb.withMisfireHandlingInstructionDoNothing();
            default:
                throw new RuntimeException("策略异常");
        }
    }
}

{#55_SysJobService_492}5.5 SysJobService定时任务调度信息接口

撰写定时任务调度的接口,主要分为初始化所有任务、新增任务,立即执行任务、更新任务、暂停任务,恢复任务和删除任务,代码如下,这个不多说,主要详细讲解一下它的实现类。

package com.zjl.service;
import org.quartz.SchedulerException;
import java.lang.reflect.InvocationTargetException;
import com.zjl.domain.SysJob;
/**
 * @author: zjl
 * @datetime: 2024/4/1
 * @desc: 定时任务调度信息
 */
public interface SysJobService {
   
    /**
     * 项目启动时,初始化定时器
     */
    void init() throws SchedulerException, NoSuchMethodException, InvocationTargetException, IllegalAccessException;
    /**
     * 新增任务
     * @param job 调度信息
     * @return 结果
     */
    public int insertJob(SysJob job) throws SchedulerException, InvocationTargetException, NoSuchMethodException, IllegalAccessException;
    /**
     * 立即运行任务
     * @param job 调度信息
     * @return 结果
     */
    public void run(SysJob job) throws SchedulerException;
    /**
     * 更新任务
     * @param job 调度信息
     * @return 结果
     */
    public int updateJob(SysJob job) throws SchedulerException, InvocationTargetException, NoSuchMethodException, IllegalAccessException;
    /**
     * 暂停任务
     * @param job 调度信息
     * @return 结果
     */
    public int pauseJob(SysJob job) throws SchedulerException;
    /**
     * 恢复任务
     * @param job 调度信息
     * @return 结果
     */
    public int resumeJob(SysJob job) throws SchedulerException;
    /**
     * 删除任务后,所对应的trigger也将被删除
     * @param job 调度信息
     * @return 结果
     */
    public int deleteJob(SysJob job) throws SchedulerException;
}

{#56_SysJobServiceImpl_548}5.6 SysJobServiceImpl定时任务调度信息接口实现类

  1. 首先initTaskList这个方法我这边做了偷懒,直接写了一个List集合在项目中,正确的配置应该是从数据库去查询一共有哪些定时任务需要程序去执行的,以及对应的配置信息应该如何去执行。
  2. 其次在init方法中,@PostConstruct这个注解会在项目启动的时候帮我们进行初始化,其次我调用了clear方法进行先清空定时任务,使用循环获取到需要所有定时任务集合,通过createScheduleJob方法去创建。
package com.zjl.service;
import com.zjl.utils.ScheduleUtils;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import com.zjl.domain.SysJob;

import static com.zjl.constant.ScheduleConstants.MISFIRE_IGNORE_MISFIRES;

/**
 * @author: zjl
 * @datetime: 2024/4/1
 * @desc:
 */
@Service
public class SysJobServiceImpl implements SysJobService {
   

    @Resource
    private Scheduler scheduler;

    /**
     * 模拟从数据库获取数据
     * @return
     */
    public List<SysJob> initTaskList(){
   
        List<SysJob> list = new ArrayList<>();
        SysJob job = new SysJob();
        job.setJobId(UUID.randomUUID().toString());
        job.setJobGroup("system");
        job.setConcurrent("0");
        job.setCronExpression("0/5 * * * * ?");
        job.setBeanTarget("task1");
        job.setBeanMethodTarget("handle");
        list.add(job);
        job = new SysJob();
        job.setJobId(UUID.randomUUID().toString());
        job.setJobGroup("system");
        job.setConcurrent("1");
        job.setCronExpression("0/50 * * * * ?");
        job.setBeanTarget("task2");
        job.setBeanMethodTarget("handle");
        job.setMisfirePolicy(MISFIRE_IGNORE_MISFIRES);
        list.add(job);
        return list;
    }

    /**
     * 初始化定时任务
     * @throws SchedulerException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    @PostConstruct
    @Override
    public void init() throws SchedulerException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
   
        scheduler.clear();
        List<SysJob> list = initTaskList();
        for (int i = 0 ; i < list.size() ; i ++){
   
            SysJob job = list.get(i);
            ScheduleUtils.createScheduleJob(scheduler, job);
        }
    }

    @Override
    public int insertJob(SysJob job) throws SchedulerException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
   
        ScheduleUtils.createScheduleJob(scheduler, job);
        return 1;
    }

    @Override
    public void run(SysJob job) throws SchedulerException {
   
        scheduler.triggerJob(JobKey.jobKey(job.getJobId(),job.getJobGroup()));
    }

    @Override
    public int updateJob(SysJob job) throws SchedulerException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
   
        // 判断是否存在
        JobKey jobKey = JobKey.jobKey(job.getJobId(),job.getJobGroup());
        if (scheduler.checkExists(jobKey)) {
   
            scheduler.deleteJob(jobKey);
        }
        ScheduleUtils.createScheduleJob(scheduler, job);
        return 1;
    }

    @Override
    public int pauseJob(SysJob job) throws SchedulerException {
   
        scheduler.pauseJob(JobKey.jobKey(job.getJobId(),job.getJobGroup()));
        return 1;
    }

    @Override
    public int resumeJob(SysJob job) throws SchedulerException {
   
        scheduler.resumeJob(JobKey.jobKey(job.getJobId(),job.getJobGroup()));
        return 1;
    }

    @Override
    public int deleteJob(SysJob job) throws SchedulerException {
   
        scheduler.deleteJob(JobKey.jobKey(job.getJobId(),job.getJobGroup()));
        return 1;
    }
}

{#_665}测试一下吧

{#_666}任务一:

package com.zjl.task;

import org.springframework.stereotype.Component;
import java.util.Date;

@Component("task1")
public class Task1 {
   
    public void handle() throws InterruptedException {
   
        String dateStr = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date());
        System.out.println("task1"+ dateStr +"开始");
        Thread.sleep(10000);
        System.out.println("task1"+ dateStr +"结束");
    }
}

{#_684}任务二:

package com.zjl.task;

import org.springframework.stereotype.Component;
import java.util.Date;

@Component("task2")
public class Task2 {
   
    public void handle(){
   
        String dateStr = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date());
        System.out.println("task2"+ dateStr +"开始");
        try {
   
            Thread.sleep(1000);
        } catch (InterruptedException e) {
   
            throw new RuntimeException(e);
        }
        System.out.println("task2"+ dateStr +"结束");
    }
}

可以分别采用并发或者非并发方式测试,反正参数都可以动态进行配置

原文链接: https://zhoujl.blog.csdn.net//article/details/137227630

标签: #Spring Boot 173 #软件开发 1171 #JAVA 991
相关文章

万字:支付“核心系统”详解 2024-11-02 15:33

专栏作者:隐墨星辰 \| 主编:陈天宇宙 这篇文章也尝试化繁为简,探寻支付系统的本质,讲清楚在线支付系统最核心的一些概念和设计理念。 虽然支付行业已经过了风头最劲的时光,但跨境支付仍然在蓬勃发展,每年依然有很多新人进入这个行业,这篇文章尝试为这些刚入行的新人提供一点帮助。 文章只介绍一些支付行业十几

资深支付架构师视角:实战从问题定义到代码落地的完整套路 2024-11-02 15:33

前言 今天从一个实际案例入手,介绍站在架构师的角度,如何识别并定义问题,提炼需求,技术方案选型,再到详细设计,最后利用AI的能力协助写出核心的代码,验证与调优。 解决问题存在一定的模式,也可以称之为框架,总结出自己的思考和解题框架,以后再碰到同类型的问题就可以如庖丁解牛一样容易。 很多年前,我写代码

Spring 实现 3 种异步接口 2024-10-18 09:07

大家好,我是苏三~ 如何处理比较耗时的接口? 这题我熟,直接上异步接口,使用 Callable、WebAsyncTask 和 DeferredResult、CompletableFuture等均可实现。 但这些方法有局限性,处理结果仅返回单个值。在某些场景下,如果需要接口异步处理的同时,还持续不断地

重学SpringBoot3-集成Redis(五)之布隆过滤器 2024-10-08 11:24

更多SpringBoot3内容请关注我的专栏:《SpringBoot3》 期待您的点赞👍收藏⭐评论✍ 重学SpringBoot3-集成Redis(五)之布隆过滤器 1. 什么是布隆过滤器? * 基本概念 适用场景 2. 使用 Redis 实现布隆过滤器 * 项目依赖 Redis 配置

设计模式第16讲——迭代器模式(Iterator) 2024-10-08 11:24

一、什么是迭代器模式 迭代器模式是一种行为型设计模式,它提供了一种统一的方式来访问集合对象中的元素,而不是暴露集合内部的表示方式。简单地说,就是将遍历集合的责任封装到一个单独的对象中,我们可以按照特定的方式访问集合中的元素。 二、角色组成 抽象迭代器(Iterator):定义了遍历聚合对象所需的方法

vue2路由和vue3路由区别及原理 2024-10-08 11:24

一、Vue2 与 Vue3 路由的区别 1. 创建路由实例方式的不同 Vue 2 中,通过 Vue.use() 注册路由插件,并通过 new VueRouter() 来创建路由实例。 import Vue from 'vue';import VueRouter from 'vue-router';i

目录

IT 外包服务商

  • 意见投递
  • zyf6619

软件开发应用

主菜单

  • 首页
  • 软件开发
  • 计算机基础
  • Hello Halo
  • 新手必读
  • 关于本知识库
Copyright © 2024 your company All Rights Reserved. Powered by Halo.