当前位置: 首页 > news >正文

java每日精进 5.27【异步实现】

第一部分:异步任务实现的逐步解析

项目通过  spring-boot-starter-job 技术组件提供异步任务功能,利用 Spring 的 @Async 注解和线程池执行异步操作。结合 TransmittableThreadLocal 解决上下文传递问题(如多租户上下文)。以下以 API 访问日志模块 的异步记录为例,逐步解析实现过程。

1.1 异步任务实现原理

异步任务实现基于以下步骤:

  1. 启用异步支持:通过 @EnableAsync 启用 Spring 的异步功能,配置线程池。
  2. 上下文传递:使用 TransmittableThreadLocal(TTL)确保异步线程继承主线程的上下文(如租户 ID)。
  3. 添加 @Async 注解:在需要异步执行的方法上添加 @Async,将其提交到线程池执行。
  4. 业务逻辑:异步方法调用核心逻辑(如插入日志),不阻塞主线程。

1.2 代码实现步骤

步骤 1:配置异步支持

在 YudaoAsyncAutoConfiguration 类中,启用异步功能并配置线程池以支持 TransmittableThreadLocal。

// 导入必要的 Spring 注解,用于自动配置和异步支持
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 org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.BeansException;
import com.alibaba.ttl.TtlRunnable;// 使用 @AutoConfiguration 注解,标记此类为 Spring Boot 自动配置类
// 该注解表明此类会被 Spring Boot 的自动配置机制自动加载,优先级高于 @Configuration
@AutoConfiguration
// 使用 @EnableAsync 注解,启用 Spring 应用上下文中的异步方法执行支持
// 允许使用 @Async 注解的方法在独立的线程中运行
@EnableAsync
public class YudaoAsyncAutoConfiguration {// 定义一个 Spring Bean,用于自定义 ThreadPoolTaskExecutor 类型的 bean// @Bean 注解将方法的返回值注册为 Spring 容器管理的 bean// 返回值: BeanPostProcessor 类型的 bean,用于在 bean 初始化时进行自定义处理@Beanpublic BeanPostProcessor threadPoolTaskExecutorBeanPostProcessor() {// 返回一个匿名内部类,实现 BeanPostProcessor 接口// BeanPostProcessor 是一个 Spring 扩展点,允许在 bean 生命周期中对其进行自定义处理return new BeanPostProcessor() {// 实现 BeanPostProcessor 接口的 postProcessBeforeInitialization 方法// 该方法在 bean 初始化之前(例如 @PostConstruct 之前)被调用// 用途: 检查 bean 是否为 ThreadPoolTaskExecutor 类型,并为其添加任务装饰器// 输入参数://   - bean: 当前正在处理的 bean 实例(Spring 容器中的任意 bean)//   - beanName: 该 bean 在 Spring 应用上下文中的名称// 返回值: 返回修改后的 bean 实例,或原 bean 实例(如果未修改)// 异常: 如果 bean 处理过程中发生错误,抛出 BeansException@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 判断当前 bean 是否为 ThreadPoolTaskExecutor 类型的实例// 如果不是,则直接返回原 bean,不做任何修改if (!(bean instanceof ThreadPoolTaskExecutor)) {return bean;}// 将 bean 转换为 ThreadPoolTaskExecutor 类型// ThreadPoolTaskExecutor 是 Spring 提供的线程池任务执行器,用于异步任务处理ThreadPoolTaskExecutor executor = (ThreadPoolTaskExecutor) bean;// 为线程池任务执行器设置任务装饰器,使用 Alibaba 的 TtlRunnable// TtlRunnable 是 Alibaba TransmittableThreadLocal 的工具类,用于在异步线程中传递 ThreadLocal 变量// 作用: 确保 ThreadLocal 变量(例如上下文信息)在异步任务中可以被正确传递和访问executor.setTaskDecorator(TtlRunnable::get);// 返回修改后的 ThreadPoolTaskExecutor 实例return executor;}};}
}

解释

  • @EnableAsync:启用 Spring 的异步支持,允许使用 @Async 注解。
  • BeanPostProcessor:拦截 ThreadPoolTaskExecutor bean 的初始化过程,添加 TtlRunnable 装饰器。
  • TransmittableThreadLocal:由 Alibaba 提供的 TTL 库(com.alibaba:transmittable-thread-local)确保线程上下文(如租户 ID)从主线程传递到异步线程。
  • TtlRunnable:TTL 提供的装饰器,将主线程的上下文包装到异步任务中,解决异步执行时上下文丢失问题(如 TenantContextHolder 的租户 ID)。
步骤 2:引入依赖

在 yudao-module-system-infra 模块中,引入 yudao spring-boot-starter-job 依赖以启用异步功能。

<dependency><groupId>cn.iocoder.boot</groupId><artifactId>yudao spring-boot-starter-job</artifactId>
</dependency>

解释

  • 依赖作用:yudao spring-boot-starter-job 提供异步任务和定时任务的支持,包含必要的线程池配置和 TTL 集成。
  • 模块化:yudao 项目将异步功能封装为 starter,方便模块复用。
步骤 3:定义异步接口方法

在 ApiAccessLogApi 接口中,定义异步方法 createApiAccessLogAsync,并添加 @Async 注解。

public interface ApiAccessLogApi {/*** 创建 API 访问日志** @param createDTO 创建信息*/void createApiAccessLog(@Valid ApiAccessLogCreateReqDTO createDTO);/*** 【异步】创建 API 访问日志** @param createDTO 访问日志 DTO*/@Asyncdefault void createApiAccessLogAsync(ApiAccessLogCreateReqDTO createDTO) {createApiAccessLog(createDTO);}
}

解释

  • createApiAccessLog:同步方法,执行日志插入逻辑。
  • createApiAccessLogAsync:异步方法,通过 @Async 标记,调用同步方法。default 关键字允许在接口中提供默认实现。
  • @Async:指示 Spring 将方法提交到线程池异步执行,调用后立即返回,不阻塞主线程。
步骤 4:实现服务逻辑

在 ApiAccessLogApiImpl 和 ApiAccessLogServiceImpl 类中,实现日志插入逻辑。

@Service
@Validated
public class ApiAccessLogApiImpl implements ApiAccessLogApi {@Resourceprivate ApiAccessLogService apiAccessLogService;@Overridepublic void createApiAccessLog(ApiAccessLogCreateReqDTO createDTO) {apiAccessLogService.createApiAccessLog(createDTO);}
}
@Service
@Validated
@Slf4j
public class ApiAccessLogServiceImpl implements ApiAccessLogService {@Resourceprivate ApiAccessLogMapper apiAccessLogMapper;@Overridepublic void createApiAccessLog(ApiAccessLogCreateReqDTO createDTO) {ApiAccessLogDO apiAccessLog = BeanUtils.toBean(createDTO, ApiAccessLogDO.class);apiAccessLog.setRequestParams(StrUtils.maxLength(apiAccessLog.getRequestParams(), REQUEST_PARAMS_MAX_LENGTH));apiAccessLog.setResultMsg(StrUtils.maxLength(apiAccessLog.getResultMsg(), RESULT_MSG_MAX_LENGTH));if (TenantContextHolder.getTenantId() != null) {apiAccessLogMapper.insert(apiAccessLog);} else {// 忽略租户上下文,避免插入失败TenantUtils.executeIgnore(() -> apiAccessLogMapper.insert(apiAccessLog));}}
}

解释

  • ApiAccessLogApiImpl:实现接口,调用 ApiAccessLogService 的同步方法。
  • ApiAccessLogServiceImpl
    • 转换 DTO 为 DO(ApiAccessLogDO)。
    • 限制请求参数和结果消息的长度(REQUEST_PARAMS_MAX_LENGTH, RESULT_MSG_MAX_LENGTH)。
    • 处理多租户:如果上下文有租户 ID,直接插入;否则使用 TenantUtils.executeIgnore 忽略租户隔离插入日志。
  • 异步调用:业务代码调用 createApiAccessLogAsync,该方法通过 @Async 在线程池中执行 createApiAccessLog,不阻塞主线程。
步骤 5:使用异步方法

在业务逻辑中,调用 ApiAccessLogApi.createApiAccessLogAsync 异步记录日志。

1.3 实现总结

  • 异步支持:通过 @EnableAsync 和 ThreadPoolTaskExecutor 启用异步,配置 TTL 解决上下文传递。
  • 依赖:引入 yudao spring-boot-starter-job,提供线程池和异步功能。
  • 方法定义:在接口中定义异步方法,添加 @Async 注解,调用同步逻辑。
  • 业务逻辑:异步方法插入日志,结合多租户支持,确保数据正确性。
  • 优势:异步记录日志不阻塞主线程,提升系统性能。

相关文章:

  • SQL计算列
  • vue展示修改前后对比,并显示修改标注diff
  • YOLOv2 深度解析:目标检测领域的进阶之路
  • 借教室--二分+查分
  • 柠檬(lemon)是什么东西?
  • leetcode:1688. 比赛中的配对次数(python3解法,数学相关算法题)
  • 深耕数字化赛道,联众优车以创新风控体系构筑汽车金融护城河
  • 【脚本】一键部署脚本
  • DH加密详解
  • SD08_解决由于anaconda版本过低无法安装高版本python的问题
  • camera_venc_thread线程获取高分辨率编码码流
  • PH热榜 | 2025-05-27
  • MySQL connection close 后, mysql server上的行为是什么
  • Python 实现简易版的文件管理(结合网络编程)
  • 一键重装Windows/Linux系统,支持虚拟服务器
  • redis高并发问题
  • (自用)Java学习-5.15(模糊搜索,收藏,购物车)
  • 公共场所人脸识别设备备案合规要点
  • 实战分享:DolphinScheduler 中 Shell 任务环境变量最佳配置方式
  • Python 实现桶排序详解
  • 学校网站建设的意义/产品推广文案怎么写
  • 网站域名备案号查询/房地产销售技巧和话术
  • 芜湖县住房建设局网站/拉新app推广平台排名
  • 常州个人做网站/成都网多多
  • 晚上必看的正能量直播app/seo流量的提升的软件
  • 网站公司怎么做/seo研究中心论坛