java基于redis实现分布式定时任务的实现

java基于redis实现分布式定时任务的实现

使用初衷

多个服务,定时任务日常使用中设计到问题

  1. 数据统计 ,会导致数据重复统计;
  2. 发送短信 ,重复发送;
  3. 优惠券,重复发送;
  4. 目前我举例这几个,欢迎补充

目前主流的xxl-job

1.由于xxl-job需要部署,以及需要数据库,不熟悉的人可能使用会有问题;
2.由于系统设计到金额,数据统计等,xxl-job需要登入后台设置,密码可能会被破解,出于安全考虑问题,
 不使用此方法

实现步骤

1. 由于导入redis的jar包简单,省略

2. 切面注解

package com.redis.base.config;
 
import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RedisLock {
    /**
     * 锁的有效时间长,单位:秒
     *
     * @return
     */
    int expireTime() default 10;
 
    /**
     * 自定义锁的keyName(不用包含namespace,内部已实现)
     */
    String keyName() default "";
}

3. 代码实现

@Slf4j
@Aspect
@Component
public class RedisLockAspect {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
	
	//annotation包后面需要制指定切换。
    @Around("execution(* *.*(..)) && @annotation(com.redis.base.config.RedisTryLock)")
    public void redisTryLockPoint(ProceedingJoinPoint pjp) {
        String defKey = "redis:lock:";
        RedisTryLock annotation;
        Method method = null;
        //获得所在切点的该类的class对象
        Class<?> aClass = pjp.getTarget().getClass();
        //获取该切点所在方法的名称,每一个使用切面的方法
        String name = pjp.getSignature().getName();
        try {
            //通过反射获得该方法
            method = aClass.getMethod(name);
            //获得该注解
            annotation = method.getAnnotation(RedisTryLock.class);
            //获取注解对应的值keyName,expireTime
            String keyName = annotation.keyName();
            int expireTime = annotation.expireTime();
            String ip =127.0.0.1; //根据实际情况获取ip地址
            // 设置redis键值
            defKey = StringUtils.isBlank(keyName) ? aClass.getName() + defKey + aClass.getDeclaringClass() + method.getName() : aClass.getName() + defKey + keyName;
 
            //根据redis 锁的原理判断是否执行成功,设值成功说明其他服务器没有执行定时任务,反则正在执行
            String v = stringRedisTemplate.opsForValue().get(RedisKey.TASK_INSTANCE_PREFIX + ip); //如果将此值改成0则任务不执行
            boolean equals = "1".equals(v) && Boolean.TRUE.equals(stringRedisTemplate.opsForValue().setIfAbsent(defKey, ip, expireTime, TimeUnit.SECONDS));
            log.info("任务:{},是否可执行:{}", defKey,equals);
            if (equals) {
                pjp.proceed();
                stringRedisTemplate.delete(defKey);
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            log.error("Facet aop failed error {}", e.getLocalizedMessage());
            stringRedisTemplate.delete(defKey);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            if (method != null) {
                log.info("方法名{},执行失败,错误信息", method.getName(), throwable);
            } else {
                log.info("方法名,执行失败,错误信息", throwable);
            }
            stringRedisTemplate.delete(defKey);
        }
    }
}

4. 在方法执行示例

@Component
@Slf4j
public class Test{

    @Scheduled(fixedDelay = 100)
    @RedisLock(keyName = "test")
  	//keyName的键值可以不写,默认读取方法名。
    public void test() {
        //方法实现
    }
}
  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 可以使用 Redis 实现定时任务,通过 Redis 的消息队列机制来实现。 下面是一个简单的示例: 1. 引入 Jedis 依赖: ```xml <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.5.2</version> </dependency> ``` 2. 创建一个 Redis 连接: ```java Jedis jedis = new Jedis("localhost"); ``` 3. 将定时任务添加到 Redis 的消息队列中: ```java // 假设当前时间是 2022-01-01 00:00:00 long timestamp = 1640995200000L; // 2022-01-01 00:00:00 的时间戳 jedis.zadd("tasks", timestamp, "task1"); // 将任务 task1 添加到 tasks 队列中,并设置执行时间为 2022-01-01 00:00:00 ``` 4. 创建一个线程,用于从 Redis 的消息队列中获取任务并执行: ```java Thread thread = new Thread(() -> { while (true) { // 从 Redis 中获取最近的一个任务 Set<String> tasks = jedis.zrangeByScore("tasks", 0, System.currentTimeMillis(), 0, 1); if (!tasks.isEmpty()) { String task = tasks.iterator().next(); // 执行任务 System.out.println("执行任务:" + task); // 从队列中删除任务 jedis.zrem("tasks", task); } try { // 休眠 1 秒钟 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); ``` 上面的代码中,我们创建了一个线程,用于从 Redis 的消息队列中获取最近的一个任务并执行。线程会每隔一秒钟检查一次是否有待执行的任务。 注意:上面的代码只是一个简单的示例,实际生产环境中,还需要考虑任务并发执行、任务超时等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值