使用Aspect的@Around注解实现定时任务执行

本文介绍了一个使用Spring Boot的CPS任务Aspect,通过Redis的SetNX操作来控制定时任务执行。它根据`ScheduledSwitchConfig`的开关状态和方法名来决定是否执行`scheduledCpsWallet`或`scheduledWallet`方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.jumi.microservice.redissetnx;
import com.jumi.microservice.common.exception.BaseException;
import com.jumi.microservice.config.ScheduledSwitchConfig;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class CpsTaskAspect {
    @Value("${spring.application.name}")
    private String projectName;
    @Resource
    private RedisTemplate<Object, Object> redisTemplate;
    @Resource
    ScheduledSwitchConfig scheduledSwitchConfig;
    /**
     * ProceedingJoinPoint:
     * -- point
     * -- 切入点对象
     * -- point.getSignature().getName() 【执行方法】
     * execution:
     * -- 定义在microservice包和所有子包里的任意类的任意方法的执行
     * -- execution(* com.jumi.microservice..*.*(..))
     * annotation:
     * -- 自定义的注解对象
     * -- @annotation(org.springframework.scheduling.annotation.Scheduled)
     */
    @Around("execution(* com.jumi.microservice..*.*(..)) && @annotation(org.springframework.scheduling.annotation.Scheduled)")
    public Object task(ProceedingJoinPoint point) {
        /*
         * 控制器开关为0
         * 执行方法 不是 scheduledCpsWallet
         * 执行方法 不是 scheduledWallet
         */
        
//        /*
//         * coupon服务【coupon-provider】
//         * ScheduledSwitchConfig配置类
//         */
//        @Configuration
//        @RefreshScope
//        public class ScheduledSwitchConfig {
//            @Value("${scheduler.enable}")
//            private String flag;
//
//            public String getFlag() {
//                return flag;
//            }
//            public void setFlag(String flag) {
//                this.flag = flag;
//            }
//        }
        
//        /*
//         * coupon服务【coupon-provider】
//         * CouponServiceImpl实现类
//         */
//        @Scheduled(cron = "0 0 3 * * ?")
//        public void scheduledCpsWallet(){
//            List<Map<String, BigDecimal>> listMap = userWalletMapper.listDayWaitCashByTime();
//            for(Map<String,BigDecimal> map:listMap){
//                redisTemplate.opsForValue().set(userLastDayWaitCash.concat(String.valueOf(map.get("userId"))),
//                        String.valueOf(map.get("amount")));
//            }
//        }
        
//        /*
//         * wallet服务【wallet-provider】
//         * WalletServiceImpl实现类
//         */
//        @Scheduled(cron = "0 0 3 * * ?")
//        public void scheduledWallet(){
//            List<Map<String,BigDecimal>> listMap = userWalletMapper.listDayWaitCashByTime();
//            for(Map<String,BigDecimal> map:listMap){
//                redisTemplate.opsForValue().set(userLastDayWaitCash.concat(String.valueOf(map.get("userId"))),
//                        String.valueOf(map.get("amount")));
//            }
//        }
        if (
                "0".equals(scheduledSwitchConfig.getFlag())
                && !"scheduledWallet".equals(point.getSignature().getName())
                && !"scheduledCpsWallet".equals(point.getSignature().getName())
        ) {
            return null;
        }
        String key = projectName + "::" + point.getSignature().getName();
        Boolean result = redisTemplate.opsForValue().setIfAbsent(key, "", 29, TimeUnit.SECONDS);
        if (result != null && result) {
            try {
                return point.proceed();
            } catch (Throwable e) {
                redisTemplate.delete(key);
                e.printStackTrace();
                throw new BaseException(500, "定时任务出错 :" + e.getMessage());
            }
        }
        return null;
    }
}

在Spring Security中,如果你想要执行一个定时任务并且希望跳过其内置的安全拦截,你可以采取以下几种策略: 1. **@PreAuthorize("permitAll")**: 如果这个定时任务是一个公共的服务或方法,可以在其上面添加`@PreAuthorize("permitAll")`注解,告诉Spring Security允许所有用户访问。 ```java @Service public class MyScheduledTask { @PreAuthorize("permitAll") public void executeTask() { //... } } ``` 2. **Spring AOP切面编程**: 创建一个通知(advice),在执行定时任务的方法上应用这个通知。例如,使用AspectJ或Spring的`@Around`注解,仅在特定的时间窗口内让任务不受安全检查。 ```java @Aspect @Component public class SecurityOverrideAspect { @Around("@annotation(scheduled)") public Object skipSecurity(ProceedingJoinPoint joinPoint) throws Throwable { // ... 确定是否正在执行定时任务 if (isScheduled()) { return joinPoint.proceed(); // 让方法继续执行 } else { // 正常的Spring Security拦截 return joinPoint.proceed(); } } private boolean isScheduled() { // 检查当前时间或其他条件判断是否为定时任务执行时刻 } } ``` 3. **Spring Boot Actuator**: 如果你使用Spring Boot,可以利用Actuator的"/info"或自定义管理端点,通过HTTP请求来执行任务,而绕过Spring Security。 4. **禁用Spring Security**: 在生产环境中不推荐这样做,但在测试或某些特殊场景下,可以在启动时临时关闭Spring Security,执行完任务后再恢复。这通常通过修改配置文件并在特定上下文里关闭security manager实现。 请注意,每个选项都有其潜在的风险,如安全性降低或难以维护。最好是在理解需求的基础上选择最适合的方法,并确保不会对整体系统的安全性造成影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值