1、启动类加上@EnableScheduling、@EnableAsync
2、创建定时任务类
@Component
public class updateContractHistory {
private final ContractHistoryService contractHistoryService;
@Autowired
public updateContractHistory(ContractHistoryService contractHistoryService) {
this.contractHistoryService = contractHistoryService;
}
@Scheduled(cron = "0 0 0 * * ? ")
public void executeUpdateCountdownDays() {
//定时任务业务逻辑
}
}
3、多线程环境下配置多线程配置
package com.jsh.erp.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
public class TimerTaskConfig {
@Bean
public Executor taskTimeOutExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(30);
executor.setThreadNamePrefix("MyTaskExecutor-");
executor.initialize();
return executor;
}
}
4、以下是一个示例代码,展示了如何在Mybatis-Plus中配置租户解析器,以便在定时任务中使用:
@Service
public class TenantConfig {
@Bean
public PaginationInterceptor paginationInterceptor(HttpServletRequest request) {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
List<ISqlParser> sqlParserList = new ArrayList<>();
TenantSqlParser tenantSqlParser = new TenantSqlParser();
tenantSqlParser.setTenantHandler(new TenantHandler() {
@Override
public Expression getTenantId() {
String token = request.getHeader("X-Access-Token");
Long tenantId = Tools.getTenantIdByToken(token);
if (tenantId != 0L) {
return new LongValue(tenantId);
} else {
//超管
return null;
}
}
@Override
public String getTenantIdColumn() { //租户字段
return "tenant_id";
}
@Override
public boolean doTableFilter(String tableName) {
//获取开启状态
Boolean res = true;
String token = request.getHeader("X-Access-Token");
Long tenantId = Tools.getTenantIdByToken(token);
if (tenantId != 0L) {
// 这里可以判断是否过滤表
if ("tyjt_employee_detail".equals(tableName) || "tyjt_form_template".equals(tableName)) {
res = true;
} else {
res = false;
}
}
return res;
}
});
sqlParserList.add(tenantSqlParser);
paginationInterceptor.setSqlParserList(sqlParserList);
paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() {
@Override
public boolean doFilter(MetaObject metaObject) {
MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);
// 过滤自定义查询此时无租户信息约束出现
});
return paginationInterceptor;
}
/**
* 相当于顶部的:
* {@code @MapperScan("com.tyjt.erp.datasource.mappers*")}
* 这里可以扩展,比如使用配置文件来配置扫描Mapper的路径
*/
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer();
scannerConfigurer.setBasePackage("com.xxx.xxx.xxx.mappers*");
return scannerConfigurer;
}
/**
* 性能分析拦截器,不建议生产使用
*/
// @Bean
// public PerformanceInterceptor performanceInterceptor(){
// return new PerformanceInterceptor();
// }
}
其中,getTenantId()方法从请求中获取租户ID,并返回一个LongValue对象;getTenantIdColumn()方法返回租户ID所在的列名;doTableFilter()方法用于过滤不需要使用租户ID的表。
5、如果报没有线程绑定错误,添加一个线程绑定就可以了。
@Component
public class updateContractHistory {
private final ContractHistoryService contractHistoryService;
@Autowired
public updateContractHistory(ContractHistoryService contractHistoryService) {
this.contractHistoryService = contractHistoryService;
}
@Scheduled(cron = "0 0 0 * * ? ")
public void executeUpdateCountdownDays() {
// 获取当前线程绑定的RequestAttributes,如果不存在则创建一个新的
RequestAttributes obj = RequestContextHolder.getRequestAttributes();
// 检查获取的RequestAttributes是否为空
if (obj == null) {
// 创建一个新的ServletRequestAttributes对象,并传入一个NonWebRequestAttributes实例作为参数
// 这里NonWebRequestAttributes是一个自定义类,用于处理非Web请求的场景,实现HttpServletRequest接口并重写所有方法即可(重写的方法不进行逻辑编写)
obj = new ServletRequestAttributes(new NonWebRequestAttributes());
}
// 将创建或获取的RequestAttributes重新绑定到当前线程
RequestContextHolder.setRequestAttributes(obj);
//接下来写对于的定时任务的业务即可
}
}
大部分内容转自如下
原文链接:https://blog.csdn.net/m0_48114733/article/details/131631351