在 Spring 框架中,可以使用定时任务来执行周期性或延迟执行的任务。Spring 提供了多种方式来配置和管理定时任务。有Java自带的java.util.Timer类,也有强大的调度器Quartz,还有SpringBoot自带的Scheduled。
在实际应用中,如果没有分布式场景(quartz 支持分布式, schedule 不支持(需要自己实现,用分布式锁),schedule跟spring结合的更好,还是很适用的。
以下介绍的是使用@Scheduled 注解的方式:
1、在启动类上添加@EnableScheduling 注解来开启定时器任务
2、在实现类的方法上添加@Scheduled 注解并设置相关参数
@Scheduled(cron = "0 22 14 * * ? ")@Overridepublic void testSchedule() {System.out.println("测试定时器");log.debug("定时任务已启动");}
3、相关参数
cron:cron表达式,指定任务在特定时间执行;
图片来源:Cron - 在线Cron表达式生成器
fixedDelay:表示上一次任务执行完成后多久再次执行,参数类型为long,单位ms;
fixedDelayString:与fixedDelay含义一样,只是参数类型变为String;
fixedRate:表示按一定的频率执行任务,参数类型为long,单位ms;
fixedRateString: 与fixedRate的含义一样,只是将参数类型变为String;
initialDelay:表示延迟多久再第一次执行任务,参数类型为long,单位ms;
initialDelayString:与initialDelay的含义一样,只是将参数类型变为String;
zone:时区,默认为当前时区,一般没有用到。
4、实现用户的预加载功能
业务分析:
(1)预加载能够访问系统的用户(即用户数据存在在数据库中)
实现逻辑:查找数据库中所有有效用户放入availableUsers哈希表中;
给有效用户设置缓存过期的时间,超时删除availableUsers表中该用户缓存。
(2)每个用户有60s时间登录访问系统,超出60秒,从系统中删除
需要判断:该用户是否存在(数据库)
该用户是否超时(能否访问系统)
5、部分代码示例
UserService层接口方法
/*** 1、从数据库查出所有用户放入 aviableUsers*/void preLoginUser();//2、redis VIP用户登录预加载,超时删除该用户void preStoreUserInRedis(long roleId);//3、使用上面preStoreUserInRedis方法将roleId=1的有效用户放入vipLoginUsers哈希表中void vipLogin(String username, String password);
UserServiceImpl实现类
//1、查找数据库中所有有效用户放入availableUsers哈希表中@Scheduled(cron = "0 06 16 * * ?")@Overridepublic void preLoginUser() {List<User> users = userDao.findAll();users.forEach(u->objectRedisTemplate.opsForHash().put("availableUsers","availableUsers:"+u.getUsername(),u));objectRedisTemplate.expire("loginUsers",1, TimeUnit.DAYS);}//2、redis VIP用户登录预加载,超时删除该用户@Overridepublic void preStoreUserInRedis(long roleId) {
// List<User> users = userDao.findAll();
// users.forEach(u->
// objectRedisTemplate.opsForHash().
// put("loginUser","loginUser:"+u.getUsername(),u));
// objectRedisTemplate.expire("loginUser",60, TimeUnit.SECONDS);
//// Set<Object> availableUsers = redisTemplate.opsForHash().keys("availableUsers");//所有用户//System.out.println(availableUsers);//System.out.println("--->"+redisTemplate.opsForHash().entries("availableUsers"));Map<Object, Object> map = objectRedisTemplate.opsForHash().entries("availableUsers");//对所有有效用户遍历map遍历map.forEach((k,v)->{User user = (User) v;if(user.getRoleId().intValue()==roleId){ //如果角色为1,放入活动d的redis缓存objectRedisTemplate.opsForHash().put("vipLoginUsers","vipLoginUsers:"+user.getUsername(),user);}});objectRedisTemplate.expire("vipLoginUsers",60, TimeUnit.SECONDS);}//3、使用上面preStoreUserInRedis方法将roleId=?的有效用户放入vipLoginUsers哈希表中//另外,加入异常@Overridepublic void vipLogin(String username, String password) {/*使用 Redis 的 opsForHash().get() 方法从名为 "availableUsers" 的 Hash 中获取键key为 "availableUsers:" + username 的值value,并将其赋给 availableUsers 对象。如果获取到的值为空,则表示该用户不存在。如果用户不存在,在下一行将会抛出自定义异常 IlegealUserException。*/Object availableUsers = objectRedisTemplate.opsForHash().get("availableUsers", "availableUsers:" + username);if(Objects.isNull(availableUsers)) throw new IlegealUserException("用户不存在异常");Object vip = objectRedisTemplate.opsForHash().get("vipLoginUsers", "vipLoginUsers:" + username);if(Objects.isNull(vip)) throw new NotVipException("不是有效的vip用户禁止登录");/*总的来说,这段代码用于进行 VIP 用户登录验证。首先,从 Redis 中获取用户名对应的用户信息 aviableUsers,如果为空,表示用户不存在,会抛出 IlegealUserException 异常。然后,从 Redis 中获取用户名对应的 VIP 用户信息 vip,如果为空,表示用户不是 VIP 用户,会抛出 NotVipException 异常。如果两个条件都满足,则表示用户存在且为 VIP 用户,可以进行后续操作。*/}
控制层
//3、VIP用户按时登录完成@GetMapping("/vipLogin")public HttpResp vipLogin(String username, String password){userService.vipLogin(username,password);return HttpResp.success("按时登录完成");}//2、预先加载所有vip客户到缓存中,根据roleId=?查询出的(业务实现层)@GetMapping("/setVip")public HttpResp setVip(long roleId){userService.preStoreUserInRedis(roleId);return HttpResp.success("预先加载所有vip客户到缓存中");}
参考:
SpringBoot学习-(十九)SpringBoot定时器#Schedule_wx6345200418f8c的技术博客_51CTO博客
https://www.cnblogs.com/toutou/p/9802955.html
感谢阅读,码字不易,多谢点赞!如有不当之处,欢迎反馈指出,感谢!