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

实现动态增QuartzJob,通过自定义注解调用相应方法

:::tip
动态增加Quartz定时任务,通过自定义注解来实现具体的定时任务方法调用。
:::
相关依赖如下

<!-- 用来动态创建 Quartz 定时任务 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

1. 注解及相关实体类

1. TaskDesc注解

用于描述定时任务的方法名和描述信息, 方便

import java.lang.annotation.*;/*** @author eleven* @date 2025/2/25 9:45* @apiNote*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TaskDesc {String methodName();String desc();
}

2. 任务实体类

@Data
@TableName("sys_task_config")
@ApiModel(value="定时任务配置")
public class TaskConfig extends BaseEntity {@ApiModelProperty("定时任务表达式")private String cron;@ApiModelProperty("执行类的全限定名")private String execClass;@ApiModelProperty("方法名")private String execMethod;@ApiModelProperty("是否运行")private Boolean startFlag;@ApiModelProperty("任务名称")private String cronName;public String getExecMethod() {return StrUtil.isNotBlank(execMethod) ? execMethod.replace("()", "").trim() : execMethod;}public String getExecClass() {return StrUtil.isNotBlank(execClass) ? execClass.trim(): execClass;}public String getCron() {return StrUtil.isNotBlank(cron) ? cron.trim() : cron;}
} 

3. 可选任务配置 vo

用于前端展示,前端配置定时任务的时候只能从 @TaskDesc 注解中获取到的方法名中选择。
也是为了限制前端用户乱填方法名,避免定时任务执行失败

@Data
public class TaskDescVo {private Integer index;private String beanName;private String className;private String methodName;private String desc;
} 

4. 任务执行记录

@Data
@TableName("credit_task_run_log")
@ApiModel("定时任务日志")
public class TaskRunLog extends BaseEntity<TaskRunLog> {@NotBlank(message = "任务id不能为空")private String taskId;@ApiModelProperty("任务开始时间")private LocalDateTime runTime;@ApiModelProperty("任务完成时间")private LocalDateTime completedTime;@ApiModelProperty("任务间隔时间")private Long intervalSeconds;@ApiModelProperty("任务运行状态")private Boolean runFlag;@ApiModelProperty("任务运行消息")private String message;public LocalDateTime getRunTime() {return getTime(runTime);}public LocalDateTime getCompletedTime() {return getTime(completedTime);}public LocalDateTime getTime(LocalDateTime time) {return Optional.ofNullable(time).orElse(LocalDateTime.now());}public Long getIntervalSeconds() {return Math.abs(Duration.between(getRunTime(), getCompletedTime()).getSeconds());}
}

5. CronDto

前端传入选择的执行时间,通过CronUtil生成cron表达式

import lombok.Data;import javax.validation.constraints.NotNull;
import java.util.List;/*** @author eleven* @date 2023/12/6 8:19* @apiNote*/
@Data
public class CronDto {/*** 选择的小时*/@NotNull(message = "执行小时参数不允许为空")private List<String> chooseHours;/*** 选择的天数*/private List<String> chooseDays;/*** 选择周几执行*/private List<String> chooseDayOfWeeks;
}

2. 定时任务配置

1. PostRunner

用于在项目启动的时候,从数据库中获取到所有的定时任务配置,然后根据配

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import net.lesscoding.task.domain.TaskConfig;
import net.lesscoding.task.service.TaskConfigService;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.util.List;/*** @author eleven* @date 2024/11/11 15:01* @apiNote*/
@Component
@Slf4j
public class PostRunner {@Autowiredprivate TaskConfigService taskConfigService;@Autowiredprivate SchedulerFactoryBean schedulerFactoryBean;@Autowiredprivate Gson gson;@PostConstructpublic void run() throws Exception {List<TaskConfig> planTaskList = taskConfigService.selectAll();log.info("==============定时任务配置中心日志开始====================");log.info("计划任务列表:{}", gson.toJson(planTaskList));log.info("==============定时任务配置中心日志结束====================");Scheduler scheduler = schedulerFactoryBean.getScheduler();if (CollUtil.isNotEmpty(planTaskList)) {for (TaskConfig planTask : planTaskList) {JobDetail jobDetail = JobBuilder.newJob(RunnerJob.class).withIdentity(planTask.getId(), StrUtil.format("{}#{}", planTask.getExecClass(), planTask.getExecMethod())).build();Trigger trigger = TriggerBuilder.newTrigger().withIdentity(planTask.getId(), StrUtil.format("{}#{}", planTask.getExecClass(), planTask.getExecMethod())).startNow().withSchedule(CronScheduleBuilder.cronSchedule(planTask.getCron())).build();scheduler.scheduleJob(jobDetail, trigger);scheduler.start();}}}
}

2. Job类

具体 Quartz 任务执行的 Job, Quartz 最终会调用 RunnerJobexecute 方法来执行定时任务

import net.lesscoding.task.service.TaskConfigService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;/*** @author eleven* @date 2024/11/11 14:22* @apiNote*/
@Slf4j
@Component
public class RunnerJob implements Job {@Autowiredprivate TaskConfigService taskConfigService;@Overridepublic void execute(JobExecutionContext jobExecutionContext) {JobDetail jobDetail = jobExecutionContext.getJobDetail();JobKey key = jobDetail.getKey();String planId = key.getName();log.info("{} trigger {}", planId, ((CronTriggerImpl) jobExecutionContext.getTrigger()).getCronExpression());log.info("{} jobKey {} time {}", planId, key, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));log.info("定时任务开始执行");try {taskConfigService.runPlan(jobDetail);} catch (Exception e) {throw new RuntimeException(e);}}
}

3. 定时任务控制器

用于前端展示定时任务配置,以及新增、修改、删除定时任务配置

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import net.lesscoding.task.core.annotations.Log;
import net.lesscoding.task.core.common.AjaxResult;
import net.lesscoding.task.core.enums.BusinessType;
import net.lesscoding.task.domain.CronDto;
import net.lesscoding.task.domain.TaskConfig;
import net.lesscoding.task.service.TaskConfigService;
import net.lesscoding.task.utils.ResultUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import javax.validation.Valid;/*** @author eleven* @date 2024/11/11 15:56* @apiNote*/@Api(tags = "定时任务配置")
@RestController
@RequestMapping("/task/config")
public class TaskConfigController {@Autowiredprivate TaskConfigService taskConfigService;@ApiOperation("查询配置列表")@PostMapping("/page")public AjaxResult page(@RequestBody TaskConfig taskConfig) {Page<TaskConfig> list = taskConfigService.getConfigList(taskConfig);return ResultUtil.success(list);}@ApiOperation("编辑配置")@PostMapping("/edit")@Log(title = "编辑定时任务配置", businessType = BusinessType.UPDATE)public AjaxResult edit(@RequestBody TaskConfig taskConfig) throws SchedulerException {return ResultUtil.toAjax(taskConfigService.editTaskConfig(taskConfig));}@PostMapping("/getCron")@ApiOperation("获取表达式")public AjaxResult getCron(@Valid @RequestBody CronDto dto) {return ResultUtil.success(taskConfigService.getCron(dto));}@ApiOperation("删除配置")@DeleteMapping("/del/{id}")@Log(title = "删除定时任务配置", businessType = BusinessType.DELETE)public AjaxResult del(@PathVariable String id) throws SchedulerException {return ResultUtil.toAjax(taskConfigService.delTaskConfig(id));}@ApiOperation("获取所有任务列表")@GetMapping("/taskList")public AjaxResult taskList() {return ResultUtil.success(taskConfigService.getAllTaskDescList());}
}

4. ServiceImpl实现类

用于实现定时任务的具体逻辑,包括获取所有任务列表、获取表达式、编辑配置、删除配置、获取配置列表、运行计划等方法

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.lesscoding.task.core.annotations.TaskDesc;
import net.lesscoding.task.core.common.GlobalException;
import net.lesscoding.task.dao.TaskConfigMapper;
import net.lesscoding.task.dao.TaskRunLogMapper;
import net.lesscoding.task.domain.CronDto;
import net.lesscoding.task.domain.TaskConfig;
import net.lesscoding.task.domain.TaskRunLog;
import net.lesscoding.task.model.vo.TaskDescVo;
import net.lesscoding.task.runner.RunnerJob;
import net.lesscoding.task.service.TaskConfigService;
import net.lesscoding.task.utils.CronUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;/*** @author eleven* @date 2024/11/11 14:21* @apiNote*/
@Service
@Slf4j
public class TaskConfigServiceImpl extends ServiceImpl<TaskConfigMapper, TaskConfig> implements TaskConfigService {@Autowiredprivate TaskConfigMapper configMapper;@Autowiredprivate TaskRunLogMapper runLogMapper;@Autowiredprivate ConfigurableListableBeanFactory beanFactory;@Autowiredprivate SchedulerFactoryBean schedulerFactoryBean;@Autowiredprivate ApplicationContext applicationContext;@Overridepublic List<TaskConfig> selectAll() {return configMapper.selectList(new QueryWrapper<>());}/*** 具体执行任务的方法* @param jobDetail Quartz的JobDetail对象,包含任务的详细信息* @return*/@Override@Asyncpublic void runPlan(JobDetail jobDetail) {JobKey key = jobDetail.getKey();String taskId = key.getName();TaskRunLog runLog = new TaskRunLog();runLog.setId(IdUtil.simpleUUID());runLog.setTaskId(taskId);runLog.setRunTime(LocalDateTime.now());TaskConfig taskConfig = configMapper.selectById(taskId);if (taskConfig == null || !taskConfig.getStartFlag()) {String logStr = StrUtil.format("任务ID {} 不存在或配置为关闭 {}", taskId, taskConfig);log.info(logStr);runLog.setRunFlag(false);runLog.setCompletedTime(LocalDateTime.now());runLog.setMessage(logStr);runLogMapper.insert(runLog);return;}String className = taskConfig.getExecClass();String methodName = taskConfig.getExecMethod();try {// 这里可以直接通过 applicationContext 获取到类的实例// Object bean = applicationContext.getBean(className);// 加载类并获取实例Class<?> execClass = getClass().getClassLoader().loadClass(className);// 从Spring容器中获取实例Object bean = beanFactory.getBean(execClass);// 获取方法Method execMethod = execClass.getDeclaredMethod(methodName);// 执行方法Object invoke = execMethod.invoke(bean);runLog.setRunFlag(true);runLog.setMessage(String.valueOf(invoke));} catch (Exception e) {runLog.setRunFlag(false);runLog.setMessage(e.getCause().getMessage());log.error("执行任务失败", e);}runLog.setCompletedTime(LocalDateTime.now());runLogMapper.insert(runLog);}@Overridepublic Page<TaskConfig> getConfigList(TaskConfig taskConfig) {PageDTO page = taskConfig.getPage();List<TaskConfig> list = configMapper.getPageByLike(page, taskConfig);page.setRecords(list);return page;}@Overridepublic int editTaskConfig(TaskConfig taskConfig) throws SchedulerException {checkEditTaskConfig(taskConfig);if (StrUtil.isBlank(taskConfig.getId())) {return saveTaskConfig(taskConfig);}return updateTaskConfig(taskConfig);}@Overridepublic int delTaskConfig(String id) throws SchedulerException {TaskConfig taskConfig = configMapper.selectById(id);deleteJob(taskConfig);return configMapper.deleteById(id);}private void checkEditTaskConfig(TaskConfig taskConfig) {boolean valid = CronUtil.isValid(taskConfig.getCron());if (!valid) {throw new GlobalException("cron表达式不合法");}try {Class<?> execClass = getClass().getClassLoader().loadClass(taskConfig.getExecClass());Object bean = beanFactory.getBean(execClass);if (bean == null) {throw new GlobalException("请检查当前类名是否存在");}Method declaredMethod = execClass.getDeclaredMethod(taskConfig.getExecMethod());if (declaredMethod == null) {throw new GlobalException(StrUtil.format("请检查当前方法{}#{}()是否存在", taskConfig.getExecClass(), taskConfig.getExecMethod()));}} catch (ClassNotFoundException e) {throw new GlobalException("请检查当前类名是否存在");} catch (NoSuchMethodException e) {throw new GlobalException(StrUtil.format("请检查当前方法{}#{}()是否存在", taskConfig.getExecClass(), taskConfig.getExecMethod()));}List<TaskConfig> allTasks = selectAll();List<TaskConfig> sameTaskList = allTasks.stream().filter(item -> StrUtil.equals(item.getExecClass(), taskConfig.getExecClass())&& StrUtil.equals(item.getExecMethod(), taskConfig.getExecMethod())).collect(Collectors.toList());if (CollUtil.isNotEmpty(sameTaskList)) {// 新增任务的时候存在相同的类名和方法名if (StrUtil.isBlank(taskConfig.getId())) {throw new GlobalException(StrUtil.format("任务{}.{}()已存在", taskConfig.getExecClass(), taskConfig.getExecMethod()));}// 修改任务的时候存在相同的类名和方法名if (sameTaskList.size() == 1 && !StrUtil.equals(sameTaskList.get(0).getId(), taskConfig.getId())) {throw new GlobalException(StrUtil.format("任务{}.{}()已存在", taskConfig.getExecClass(), taskConfig.getExecMethod()));}}}public int saveTaskConfig(TaskConfig taskConfig) throws SchedulerException {taskConfig.setId(IdUtil.simpleUUID());int effect = configMapper.insert(taskConfig);createNewScheduler(taskConfig);return effect;}public int updateTaskConfig(TaskConfig taskConfig) throws SchedulerException {deleteJob(configMapper.selectById(taskConfig.getId()));int effect = configMapper.updateById(taskConfig);createNewScheduler(taskConfig);return effect;}private void createNewScheduler(TaskConfig task) throws SchedulerException {log.info("开始执行创建新任务");Scheduler scheduler = schedulerFactoryBean.getScheduler();JobKey jobKey = jobKey(task);JobDetail jobDetail = JobBuilder.newJob(RunnerJob.class).withIdentity(jobKey).build();Trigger trigger = TriggerBuilder.newTrigger().withIdentity(task.getId(), StrUtil.format("{}#{}", task.getExecClass(), task.getExecMethod())).startNow().withSchedule(CronScheduleBuilder.cronSchedule(task.getCron())).build();scheduler.scheduleJob(jobDetail, trigger);scheduler.start();log.info("任务创建完成");}/*** 阐述job** @param task* @throws SchedulerException*/public boolean deleteJob(TaskConfig task) throws SchedulerException {Scheduler scheduler = schedulerFactoryBean.getScheduler();JobKey jobKey = jobKey(task);boolean deleteJob = scheduler.deleteJob(jobKey);log.info("当前 jobKey {} 删除结果{}", jobKey, deleteJob);return deleteJob;}private JobKey jobKey(TaskConfig task) {JobKey jobKey = new JobKey(task.getId(), StrUtil.format("{}#{}", task.getExecClass(), task.getExecMethod()));log.info("当前任务 {}, jobKey{}", task, jobKey);return jobKey;}@Overridepublic String getCron(CronDto dto) {boolean daysEmptyFlag = CollUtil.isEmpty(dto.getChooseDays());boolean dayOfWeeksEmptyFlag = CollUtil.isEmpty(dto.getChooseDayOfWeeks());if (daysEmptyFlag && dayOfWeeksEmptyFlag) {throw new RuntimeException("执行天数和星期必须选择一个");}if (!daysEmptyFlag && !dayOfWeeksEmptyFlag) {throw new RuntimeException("执行天数和星期只能选择一个");}String hours = String.join(",", dto.getChooseHours());String days = CollUtil.isEmpty(dto.getChooseDays()) ? "?" : String.join(",", dto.getChooseDays());String dayOfWeek = CollUtil.isEmpty(dto.getChooseDayOfWeeks()) ? "?" : String.join(",", dto.getChooseDayOfWeeks());String cronStr = String.format("0 0 %s %s * %s", hours, days, dayOfWeek);if (!CronUtil.isValid(cronStr)) {throw new RuntimeException("定时任务表达式不合法");}log.info("当前任务表达式 {}", cronStr);return cronStr;}@Overridepublic List<TaskDescVo> getAllTaskDescList() {List<TaskDescVo> result = new ArrayList<>();List<String> beanNames = new ArrayList<>(Arrays.asList(applicationContext.getBeanDefinitionNames()));beanNames.sort(String::compareTo);TaskDescVo vo = null;for (String beanName : beanNames) {Object bean = applicationContext.getBean(beanName);// 使用 AopUtils 来获取代理对象的原始类, 否则获得的是代理类,无法获取@Service等类上的注解Class<?> beanClass = AopUtils.getTargetClass(bean);if (beanClass.isAnnotationPresent(TaskDesc.class)) {TaskDesc annotation = beanClass.getAnnotation(TaskDesc.class);vo = new TaskDescVo();vo.setMethodName(annotation.methodName());vo.setDesc(annotation.desc());vo.setBeanName(beanName);vo.setClassName(beanClass.getName());vo.setIndex(beanNames.indexOf(beanName));result.add(vo);}}return result;}private CronDto parseCron(String cron) {String[] split = cron.split(" ");// 计算几个小时String cronHours = split[2];// 计算几天String cronDays = split[3];// 计算的周期String cronDayOfWeeks = split[5];CronDto cronDto = new CronDto();cronDto.setChooseHours(Arrays.asList(cronHours.split(",")));cronDto.setChooseDays(Arrays.asList(cronDays.split(",")));cronDto.setChooseDayOfWeeks(Arrays.asList(cronDayOfWeeks.split(",")));return cronDto;}
}

5. CronUtil

import org.quartz.CronExpression;import java.text.ParseException;
import java.util.Date;/*** cron表达式工具类** @author ruoyi*/
public class CronUtil {/*** 返回一个布尔值代表一个给定的Cron表达式的有效性** @param cronExpression Cron表达式* @return boolean 表达式是否有效*/public static boolean isValid(String cronExpression) {return CronExpression.isValidExpression(cronExpression);}public static void main(String[] args) {System.out.println(isValid("0/1 * * * * ?"));}/*** 返回一个字符串值,表示该消息无效Cron表达式给出有效性** @param cronExpression Cron表达式* @return String 无效时返回表达式错误描述,如果有效返回null*/public static String getInvalidMessage(String cronExpression) {try {new CronExpression(cronExpression);return null;} catch (ParseException pe) {return pe.getMessage();}}/*** 返回下一个执行时间根据给定的Cron表达式** @param cronExpression Cron表达式* @return Date 下次Cron表达式执行时间*/public static Date getNextExecution(String cronExpression) {try {CronExpression cron = new CronExpression(cronExpression);return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));} catch (ParseException e) {throw new IllegalArgumentException(e.getMessage());}}
}

6. @TaskDesc注解使用

@TaskDesc注解的类需要使用@Component注解标注,被SpringBoot容器管理到定时任务才能正常执行

import net.lesscoding.task.core.annotations.TaskDesc;
import net.lesscoding.task.dao.EvaluateDsCustomerMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.jexl3.JexlEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** @author eleven* @date 2025/3/12 15:11* @apiNote 客户评分计数器*/
@Component
@Slf4j
@TaskDesc(methodName = "scoreCounter", desc = "客户评分计数器")
public class CustomerScoreCounter extends AbstractScoreCounter {@Autowiredprivate EvaluateDsCustomerMapper dsCustomerMapper;@Autowiredprivate JexlEngine jexlEngine;// 定时任务实际执行的方法@Overridepublic void scoreCounter() {calcScoreAndSave(2, null, "customer_id",dsCustomerMapper.selectList(null));}
}

相关文章:

实现动态增QuartzJob,通过自定义注解调用相应方法

:::tip 动态增加Quartz定时任务&#xff0c;通过自定义注解来实现具体的定时任务方法调用。 ::: 相关依赖如下 <!-- 用来动态创建 Quartz 定时任务 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-start…...

Linux网络 网络基础一

1. 计算机网络背景 1.1 网络发展 独立模式&#xff1a;计算机之间相互独立。 网络互联&#xff1a;多台计算机连接在一起&#xff0c;完成数据共享。 局域网LAN&#xff1a;计算机数量更多了&#xff0c;通过交换机和路由器连接在一起。 广域网WAN&#xff1a;将远隔千里的…...

auto关键字解析

前言 在11标准之前&#xff0c;auto在c中是声明存储器类型的关键字。而在11标准中它的功能变为了类型推导。 对此&#xff0c; 在这里引入Cprimer中的原句&#xff1a; 编程时常常需要把表达式的值赋给变量&#xff0c;这就要求在声明变量的时候清楚的知道表达式的类型。然而…...

[实战]用户系统-1-基础功能完善

[实战]用户系统-1 目标响应格式化新建lib-interceptor增加res拦截器新建lib-filter完善异常处理日志处理新建lib-logger新增mongodb的model代码进度目标 我们的用户系统实战,将会实现以下功能,登录,注册,登出,修改用户信息,上传头像,响应的格式化,请求拦截,vip标识。…...

C#SQLServer数据库通用访问类

using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Linq; using System.Text; using System.Threading.Tasks; namespace thinger.cn.ADO.NETTeach { /// /// 数据库的通用类 /// public class SQLHelperBase…...

Linux中进程控制(上)

目录 进程创建 写时拷贝 fork常用场景 fork调用失败的原因 进程终止 进程退出场景 退出码 _exit函数 exit函数 进程等待 进程等待必要性 进程等待方法 wait方法 ​编辑 waitpid方法 获取⼦进程status 阻塞和非阻塞等待 进程创建 在linux中fork函数是⾮常重要的…...

为什么服务器突然变慢?从硬件到软件的排查方法

服务器突然变慢是许多系统管理员和网站运维人员经常遇到的问题。这种情况可能会影响网站性能、用户体验以及整个业务流程。了解服务器变慢的原因并采取相应的排查措施是至关重要的。本文将介绍服务器突然变慢的可能原因&#xff0c;从硬件到软件方面逐一排查&#xff0c;并提供…...

碳交易系统九大构成

碳交易系统九大构成 碳排放权交易系统的核心要素包括覆盖范围、配额总量、配额分配、排放监测、报送与核查&#xff0c;履约考核、抵消机制、交易机制、市场监管及配套的法律法规体系。 图源《中国碳排放权交易市场&#xff1a;从原理到实践》 1、覆盖范围 碳排放权交易体系…...

第9.2讲、Tiny Decoder(带 Mask)详解与实战

自己搭建一个 Tiny Decoder&#xff08;带 Mask&#xff09;&#xff0c;参考 Transformer Encoder 的结构&#xff0c;并添加 Masked Multi-Head Self-Attention&#xff0c;它是 Decoder 的核心特征之一。 1. 背景与动机 Transformer 架构已成为自然语言处理&#xff08;NLP…...

Java接口P99含义解析

假设你开了一家奶茶店&#xff08;接口就是你的奶茶制作流水线&#xff09;&#xff0c;每天要处理100杯订单&#xff1a; &#x1f680; P99是什么&#xff1f; 平均响应时间&#xff1a;就像说"平均每杯奶茶2分钟做好"&#xff0c;但可能有10杯让客人等10分钟P99…...

【Oracle 专栏】清理用户及表空间

Oracle相关文档&#xff0c;希望互相学习&#xff0c;共同进步 风123456789&#xff5e;-CSDN博客 1.背景 今天需要清理一台服务器中之前的库&#xff0c;目前不再使用&#xff0c;以便释放空间。 如&#xff1a;清理 NH_MCRO_COLLECT 用户 2. 实验清理 2.1 查询&#xff1a;清…...

Qt功能区:Ribbon控件

控件 1. 按钮1.1 多选按钮1.2 2. 下拉列表框SARibbonComboBox2.1 简介2.2 代码实现 1. 按钮 1.1 多选按钮 软件功能&#xff1a;用于实现Category的名称居中。 SARibbonCheckBox继承于QCheckBox&#xff0c;使用方法完全相同。 SARibbonCheckBox* checkBox new SARibbonChe…...

eclipse 生成函数说明注释

在Eclipse中生成函数说明注释&#xff08;JavaDoc风格&#xff09;可以通过以下方法实现&#xff1a; 快捷键方式&#xff1a; 将光标放在函数上方输入/**后按回车键Eclipse会自动生成包含参数和返回值的注释模板 菜单方式&#xff1a; 选中函数点击菜单栏 Source > Gen…...

【Qt】QImage实战

QImage::Format_Mono, QImage::Format_RGB32, QImage::Format_ARGB32, QImage::Format_ARGB32_Premultiplied, 和 QImage::Format_RGB555 是 Qt 中不同的图像像素格式&#xff0c;它们在存储方式、颜色深度、是否支持透明通道以及适用场景上各有不同。下面是它们的详细对比&…...

tomcat知识点

1. JDK JDK是 Java 语言的软件开发工具包,JDK是整个java开发的核心,它包含JAVA工具还包括完整的 JRE(Java Runtime Environment)Java运行环境,包括了用于产品环境的各种库类,以及给开发人员使用的补充库。 JDK包含了一批用于Java开发的组件,其中包括: javac:编译器,将…...

Linux虚拟文件系统(2)

2.3 目录项-dentry 目录项&#xff0c;即 dentry&#xff0c;用来记录文件的名字、索引节点指针以及与其他目录项的关联关系。多个关联的目录项&#xff0c;就构成了文件系统的目录结构。和上一章中超级块和索引节点不同&#xff0c;目录项并不是实际存在于磁盘上的&#xff0c…...

遥感影像-语义分割数据集:光伏数据集详细介绍及训练样本处理流程

原始数据集详情 简介&#xff1a;数据集包括504张亚米级卫星图片的农业光伏数据集&#xff0c;该数据集用于亚米级影像中的农业光伏提取任务。 KeyValue卫星类型亚米级卫星覆盖区域未知场景未知分辨率0.5m数量504张单张尺寸1024*1024原始影像位深8位标签图片位深8位原始影像通…...

【Java高阶面经:微服务篇】4.大促生存法则:微服务降级实战与高可用架构设计

一、降级决策的核心逻辑:资源博弈下的生存选择 1.1 大促场景的资源极限挑战 在电商大促等极端流量场景下,系统面临的资源瓶颈呈现指数级增长: 流量特征: 峰值QPS可达日常的50倍以上(如某电商大促下单QPS从1万突增至50万)流量毛刺持续时间短(通常2-4小时),但对系统稳…...

工业物联网网关在变电站远程监控中的安全传输解决方案

一、项目背景 随着智能电网的快速发展&#xff0c;对变电站的智能化监控需求日益迫切。传统变电站采用人工巡检和就地监控的方式&#xff0c;存在效率低、实时性差、数据不准确等问题&#xff0c;难以满足现代电力系统对变电站安全、稳定、高效运行的要求。而智能变电站通过引…...

车载诊断架构 --- LIN 节点 ECU 故障设计原则

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…...

编程技能:字符串函数09,strncmp

专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏&#xff0c;故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 &#xff08;一&#xff09;WIn32 专栏导航 上一篇&#xff1a;编程技能&#xff1a;字符串函数08&#xff0c;strcmp 回到目录…...

UML 时序图 使用案例

UML 时序图 UML 时序图 (Sequence Diagram)时序图的主要元素消息类型详解时序图示例时序图绘制步骤时序图的应用场景 UML 时序图 (Sequence Diagram) 时序图是UML(统一建模语言)中用于展示对象之间交互行为的动态视图&#xff0c;它特别强调消息的时间顺序。 时序图的主要元素…...

业务逻辑篇水平越权垂直越权未授权访问检测插件SRC 项目

# 逻辑越权 - 检测原理 - 水平 & 垂直 & 未授权 1 、水平越权&#xff1a;同级别的用户之间权限的跨越 2 、垂直越权&#xff1a;低级别用户到高级别用户权限的跨越 3 、未授权访问&#xff1a;通过无级别用户能访问到需验证应用 PHPStudy Metinfo4.0 会员后台中…...

Android开发——不同布局的定位属性 与 通用属性

目录 不同布局的定位属性1. 线性布局&#xff08;LinearLayout&#xff09;2. 相对布局&#xff08;RelativeLayout&#xff09;3. 约束布局&#xff08;ConstraintLayout&#xff09;4. 表格布局&#xff08;TableLayout&#xff09;5. 网格布局&#xff08;GridLayout&#x…...

【DB2】SQL1639N 处理

背景 测试环境21套DB2需要创建只读用户并赋予权限&#xff0c;在20套都成功的情况下&#xff0c;有一套报错了&#xff0c;具体细节为&#xff0c;赋权成功&#xff0c;但是使用被赋权的账户连接失败&#xff0c;报错如下 SQL1639N The database server was unable to perfor…...

禾纳EAT3152AP MOS电源芯片PIN TO PIN替代泰德TDM3307/2307方案

AET3152AP特性 VDS-30V,ID-40A RDS (ON)11mΩ (TYP.)VGS-10V, ID-10A RDS (ON)15mΩ (TYP.)VGS-4.5V, ID-5A 快速切换 l 低电阻 不含卤素和锑&#xff0c;符合Rohs标准 温度范围&#xff1a;-55℃~125℃ 封装&#xff1a;PDFN3030 AET3152AP应用 交换机切换 便携式/台式机中的…...

Python Day28 学习

继续聚类算法的学习 浙大疏锦行 DBSCAN聚类 Q1. 该算法的原理是什么&#xff1f; 总体而言&#xff0c;DBSCAN聚类是一种基于密度的聚类算法&#xff0c;适合发现任意形状的簇和检测噪声点 Q2. 代码实现 import numpy as np import pandas as pd from sklearn.cluster impo…...

企业网站架构部署与优化-Nginx核心功能

目录 #1.1正向代理 1.1.1编译安装Nginx 1.1.2配置正向代理 #2.1反向代理 2.1.1配置nginx七层代理 2.1.2配置nginx四层代理 1.1正向代理 正向代理&#xff08;Forward Proxy&#xff09;是一种位于客户端和目标服务器之间的服务器&#xff0c;用于代表客户端向服务器发送请求并…...

Java 多态

文章目录 多态向上转型和向下转型向上转型和重写重写和重载的区别动态绑定和静态绑定用代码来解释什么是多态向下转型 多态的优点 总结 多态 什么是多态&#xff1f;为什么要使用多态&#xff1f; 简单来说是多种形态&#xff0c;具体来说是去完成某个事情&#xff0c;当不同对…...

机器学习中的泛化能力

我们常常提到模型的泛化能力&#xff0c;什么是泛化能力呢&#xff1f; 百度百科这样解释&#xff1a;是指机器学习算法对新鲜样本的适应能力。 学习的目的是学到隐含在数据背后的规律&#xff0c;对具有同一规律的学习集以外的数据&#xff0c;经过训练的网络也能给出合适的输…...

第七章:数据存储策略与状态恢复机制实录

经过状态机、UI交互、逻辑驱动等章节的打磨&#xff0c;前端体系已经具备较强的调度与展示能力。但真正能决定组件在异常情况下能否“满血复活”的关键&#xff0c;落在了“状态恢复”这一关卡。尤其在安卓端环境复杂、网络波动频繁的前提下&#xff0c;若没有稳定的本地数据存…...

digitalworld.local: FALL靶场

digitalworld.local: FALL 来自 <digitalworld.local: FALL ~ VulnHub> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.182&#xff0c;靶场IP192.168.23.4 3&…...

Java Collection(集合) 接口

Date: 2025-05-21 20:21:32 author: lijianzhan Java 集合框架提供了一组接口和类&#xff0c;以实现各种数据结构和算法。 以下是关于 Java 集合的核心内容说明&#xff1a; /*** Java Collection Framework 说明&#xff1a;** 在 Java 中&#xff0c;集合&#xff08;Collec…...

直线型绝对值位移传感器:精准测量的科技利刃

在科技飞速发展的今天&#xff0c;精确测量成为了众多领域不可或缺的关键环节。无论是工业自动化生产线上的精细操作&#xff0c;还是航空航天领域中对零部件位移的严苛把控&#xff0c;亦或是科研实验中对微小位移变化的精准捕捉&#xff0c;都离不开一款高性能的测量设备——…...

Kotlin 极简小炒 P9 - 数组(数组的创建、数组元素的访问与修改、数组遍历、数组操作、多维数组、数组与可变参数)

Kotlin 概述 Kotlin 由 JetBrains 开发&#xff0c;是一种在 JVM&#xff08;Java 虚拟机&#xff09;上运行的静态类型编程语言 Kotlin 旨在提高开发者的编码效率和安全性&#xff0c;同时保持与 Java 的高度互操作性 Kotlin 是 Android 应用开发的首选语言&#xff0c;也可…...

Server-Driven UI:Kotlin 如何重塑动态化 Android 应用开发

以下是一篇整合详细代码示例的完整博客&#xff0c;深入探讨Kotlin在Server-Driven UI&#xff08;SDUI&#xff09;中的核心作用&#xff1a; Server-Driven UI&#xff1a;Kotlin 如何重塑动态化 Android 应用开发 1. Server-Driven UI 的核心价值 SDUI通过将UI描述与业务逻…...

基于多传感器融合的智能驾驶环境感知系统

摘要 随着自动驾驶技术的发展,单一传感器的局限性日益凸显。本文提出了一种基于多传感器(摄像头、毫米波雷达、激光雷达)融合的环境感知系统,通过深度学习算法实现车辆周围环境的精确感知。文章详细介绍了传感器标定、数据融合、目标检测与跟踪等关键技术,并提供了Python…...

JC/T 2848-2024 玻璃纤维增强石膏(GRG)装饰制品检测

玻璃纤维增强石膏装饰制品是指以玻璃纤维为主要增强材料&#xff0c;高强石膏为主要胶凝材料&#xff0c;适当掺入集料&#xff0c;外加剂的石膏装饰制品&#xff0c;GRG具有防火&#xff0c;隔音&#xff0c;被广泛应用于&#xff0c;墙板&#xff0c;装饰构件等。 JC/T 2848…...

每日算法 -【Swift 算法】寻找字符串中最长回文子串(三种经典解法全解析)

&#x1f9e9; 最长回文子串问题&#xff1a;三种经典解法全解析&#xff08;含代码注释&#xff09; 本文将系统讲解“最长回文子串”问题的三种常见解法&#xff1a;中心扩展法、动态规划、马拉车算法&#xff08;Manacher’s Algorithm&#xff09;&#xff0c;并进行对比与…...

【Java高阶面经:数据库篇】13. MySQL 并发控制秘籍:MVCC 协议与隔离级别深度解析

一、MVCC核心原理:多版本并发控制的基石 1.1 为什么需要MVCC? 在传统锁机制中,读写操作会互相阻塞,导致高并发场景下性能下降。MVCC通过多版本数据快照避免读写阻塞,实现: 读不加锁:快照读(普通SELECT)不阻塞写操作写不阻塞读:写操作生成新版本,读操作访问历史版本…...

分布式集群中的共识算法及其在时序数据库IoTDB中的应用

一、引言 在分布式集群环境中&#xff0c;为了实现海量数据的横向扩展&#xff0c;数据通常被划分为多个子集并分散存储在集群的各个节点上。为了确保数据的高可用性&#xff0c;每个数据子集都会在多个物理节点上存储副本。然而&#xff0c;这种多副本机制也带来了新的挑战&a…...

Java面试实录:从JVM调优到Spring Cloud实践

Java大厂面试&#xff1a;当严肃面试官遇上搞笑程序员 场景设定 面试官&#xff1a;拥有多年行业经验的技术专家&#xff0c;对Java及相关技术栈有着深入的理解。明哥&#xff1a;一位自认为是“水货”的程序员&#xff0c;擅长用幽默化解紧张气氛&#xff0c;但面对复杂问题…...

自定义协议与序列反序列化

目录 引子&#xff1a; 一、再谈 "协议" 二、自定义协议与网络版计算器 1.约定方案一: 2.约定方案二: 3.我们采用的协议 三、网络计算器代码 Log.hpp 日志 Makefile Socket.hpp 套接字封装 Protocol.hpp 协议 序列化反序列化 结构化数据格式规定 TcpSe…...

SAP-ABAP:ABAP异常处理与SAP现代技术融合—— 面向云原生、微服务与低代码场景的创新实践

专题三&#xff1a;ABAP异常处理与SAP现代技术融合 —— 面向云原生、微服务与低代码场景的创新实践 一、SAP技术演进与异常处理的挑战 随着SAP技术栈向云端、微服务化和低代码方向演进&#xff0c;异常处理面临新场景&#xff1a; Fiori UX敏感度&#xff1a;用户期望前端友…...

JavaScript面试题之消息队列

JavaScript消息队列详解&#xff1a;单线程的异步魔法核心 在JavaScript的单线程世界中&#xff0c;消息队列&#xff08;Message Queue&#xff09;是实现异步编程的核心机制&#xff0c;它像一位高效的调度员&#xff0c;让代码既能“一心多用”又避免卡顿。本文将深入剖析消…...

【低代码】如何使用明道云调用 Flask 视图函数并传参(POST 方法实践)

在自动化办公或业务流程管理中,明道云提供了强大的 HTTP 请求节点,可以直接调用第三方 API,包括我们常见的 Flask 服务端接口。本文将详细介绍如何使用明道云通过 POST 方法调用 Flask 视图函数并传参,包括配置要点与 Python 后端的参数接收方法。 一、场景介绍 我们希望…...

广州卓远VR受邀参加2025智能体育典型案例调研活动,并入驻国体华为运动健康联合实验室!

近日&#xff0c;“2025年智能体育典型案例调研活动”在东莞松山湖成功举办。本次调研活动由国家体育总局体育科学研究所和中国信息通信研究院联合主办&#xff0c;旨在深入贯彻中央关于培育新型消费的战略部署&#xff0c;通过激活智能健身产品消费潜力&#xff0c;加快运动健…...

【WebRTC】源码更改麦克风权限

WebRTC源码更改麦克风权限 仓库: https://webrtc.googlesource.com/src.git分支: guyl/m125节点: b09c2f83f85ec70614503d16e4c530484eb0ee4f...

spring cloud alibaba-Geteway详解

spring cloud alibaba-Gateway详解 Gateway介绍 在 Spring Cloud Alibaba 生态系统中&#xff0c;Gateway 是一个非常重要的组件&#xff0c;用于构建微服务架构中的网关服务。它基于 Spring Cloud Gateway 进行扩展和优化&#xff0c;提供了更强大的功能和更好的性能。 Gat…...

结课作业01. 用户空间 MPU6050 体感鼠标驱动程序

目录 一. qt界面实现 二. 虚拟设备模拟模拟鼠标实现体感鼠标 2.1 函数声明 2.2 虚拟鼠标实现 2.2.1 虚拟鼠标创建函数 2.2.2 鼠标移动函数 2.2.3 鼠标点击函数 2.3 mpu6050相关函数实现 2.3.1 i2c设备初始化 2.3.2 mpu6050寄存器写入 2.3.3 mpu6050寄存器读取 2.3.…...