在 Spring 框架中,可以使用定时任务来执行周期性或延迟执行的任务。Spring 提供了多种方式来配置和管理定时任务。有Java自带的java.util.Timer类,也有强大的调度器Quartz,还有SpringBoot自带的Scheduled。
在实际应用中,如果没有分布式场景(quartz 支持分布式, schedule 不支持(需要自己实现,用分布式锁),schedule跟spring结合的更好,还是很适用的。
以下介绍的是使用@Scheduled 注解的方式:
1、在启动类上添加@EnableScheduling 注解来开启定时器任务
2、在实现类的方法上添加@Scheduled 注解并设置相关参数
@Scheduled(cron = "0 22 14 * * ? ")
@Override
public 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 * * ?")
@Override
public 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用户登录预加载,超时删除该用户
@Override
public 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哈希表中
//另外,加入异常
@Override
public 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
感谢阅读,码字不易,多谢点赞!如有不当之处,欢迎反馈指出,感谢!