10.Quartz实现定时打分 热帖排行

1.Spring Quartz

(1)简介

核心组件

  1. scheduler 接口:核心调度工具,所有任务由这一接口调用

  1. job:定义任务,重写execute方法

  1. JobDetail接口:配置描述

  1. Trigger接口:什么时候运行,以什么样的频率运行

(2)Spring 整合
  • 引入依赖

  • 将配置表导入数据库

  1. qrtz_job_details:job详情配置描述表

  1. qrtz_simple_triggers:触发器相关配置简述

  1. qrtz_jtriggers:触发器相关完整配置

  1. qrtz_scheduler:定时器状态

  1. qrtz_locks:定时器锁

  • QuartzPropertie

spring.quartz.job-store-type=jdbc
spring.quartz.scheduler-name=communityScheduler 
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO 
#spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
spring.quartz.properties.org.quartz.jobStore.class=org.springframework.scheduling.quartz.LocalDataSourceJobStore
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate 
spring.quartz.properties.org.quartz.jobStore.isClustered=true 
spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool 
spring.quartz.properties.org.quartz.threadPool.threadCount=5 

BUG:从spring5.3.6使用org.quartz.impl.jdbcjobstore.JobStoreTX定义quartz的默认数据源支持,如下

org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
  • 实现我们自己的job,重写execute方法

  • 在QuartzConfig里

  • 配置 JobDetail

// 配置JobDetail
@Bean
public JobDetailFactoryBean alphaJobDetail() {
    JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
    factoryBean.setJobClass(AlphaJob.class);
    factoryBean.setName("alphaJob");
    factoryBean.setGroup("alphaJobGroup");
    factoryBean.setDurability(true);
    factoryBean.setRequestsRecovery(true);
    return factoryBean;
}
实例化JobDetailFactoryBean
声明管理的管理的是谁.setJobClass
声明job任务的名字.setName
声明任务属于的组.setGroup
声明任务是否长久保存.setDurability
声明任务是否可恢复.setRequestsRecovery
  • 配置Trigger

// 配置Trigger(SimpleTriggerFactoryBean, CronTriggerFactoryBean)
@Bean
public SimpleTriggerFactoryBean alphaTrigger(JobDetail alphaJobDetail) {
    SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
    factoryBean.setJobDetail(alphaJobDetail);
    factoryBean.setName("alphaTrigger");
    factoryBean.setGroup("alphaTriggerGroup");
    factoryBean.setRepeatInterval(3000);
    factoryBean.setJobDataMap(new JobDataMap());
    return factoryBean;
}
实例化SimpleTriggerFactoryBean
声明管理的管理的是谁.setJobClass
声明job任务的名字.setName
声明任务属于的组.setGroup
声明任务执行的频率.setRepeatInterval
声明Trigger的存储状态类型.setJobDataMap

  1. 热帖排行

用一个set将分数变化的帖子的id装起来,定时从中取出 更新

(1)统计发生分数变化的帖子

点赞 评论 精华 发布时间会影响分数

  • RedisKeyUtil

  • 添加方法统计帖子分数

// 帖子分数
public static String getPostScoreKey() {
    return PREFIX_POST + SPLIT + "score";
}
  • DiscussPostController

  • 发布帖子 设置精华 的方法里补充

// 计算帖子分数
String redisKey = RedisKeyUtil.getPostScoreKey();
redisTemplate.opsForSet().add(redisKey, post.getId());
  • CommentController

  • addComment添加评论时做处理

  • LikeController

  • like 点赞时 做处理

(2)写定时任务Job
public class PostScoreRefreshJob implements Job, CommunityConstant {

    private static final Logger logger = LoggerFactory.getLogger(PostScoreRefreshJob.class);

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private DiscussPostService discussPostService;

    @Autowired
    private LikeService likeService;

    @Autowired
    private ElasticsearchService elasticsearchService;

    // 牛客纪元
    private static final Date epoch;

    static {
        try {
            epoch = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2014-08-01 00:00:00");
        } catch (ParseException e) {
            throw new RuntimeException("初始化牛客纪元失败!", e);
        }
    }

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        String redisKey = RedisKeyUtil.getPostScoreKey();
        BoundSetOperations operations = redisTemplate.boundSetOps(redisKey);

        if (operations.size() == 0) {
            logger.info("[任务取消] 没有需要刷新的帖子!");
            return;
        }

        logger.info("[任务开始] 正在刷新帖子分数: " + operations.size());
        while (operations.size() > 0) {
            this.refresh((Integer) operations.pop());
        }
        logger.info("[任务结束] 帖子分数刷新完毕!");
    }

    private void refresh(int postId) {
        DiscussPost post = discussPostService.findDiscussPostById(postId);

        if (post == null) {
            logger.error("该帖子不存在: id = " + postId);
            return;
        }

        // 是否精华
        boolean wonderful = post.getStatus() == 1;
        // 评论数量
        int commentCount = post.getCommentCount();
        // 点赞数量
        long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, postId);

        // 计算权重
        double w = (wonderful ? 75 : 0) + commentCount * 10 + likeCount * 2;
        // 分数 = 帖子权重 + 距离天数
        double score = Math.log10(Math.max(w, 1))
                + (post.getCreateTime().getTime() - epoch.getTime()) / (1000 * 3600 * 24);
        // 更新帖子分数
        discussPostService.updateScore(postId, score);
        // 同步搜索数据
        post.setScore(score);
        elasticsearchService.saveDiscussPost(post);
    }

}
(3)配置 JobDetails Trigger
@Configuration
public class QuartzConfig {

    @Bean
    public JobDetailFactoryBean postScoreRefreshJobDetail() {
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        factoryBean.setJobClass(PostScoreRefreshJob.class);
        factoryBean.setName("postScoreRefreshJob");
        factoryBean.setGroup("communityJobGroup");
        factoryBean.setDurability(true);
        factoryBean.setRequestsRecovery(true);
        return factoryBean;
    }

    @Bean
    public SimpleTriggerFactoryBean postScoreRefreshTrigger(JobDetail postScoreRefreshJobDetail) {
        SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
        factoryBean.setJobDetail(postScoreRefreshJobDetail);
        factoryBean.setName("postScoreRefreshTrigger");
        factoryBean.setGroup("communityTriggerGroup");
        factoryBean.setRepeatInterval(1000 * 60 * 5);
        factoryBean.setJobDataMap(new JobDataMap());
        return factoryBean;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
org.springframework.scheduling.quartz.CronTriggerBean是Spring框架中的一个定时任务配置类,可以用来设置基于Cron表达式的定时任务。具体使用方法如下: 1. 配置依赖项 在pom.xml文件中添加以下依赖项: ``` <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>${quartz.version}</version> </dependency> ``` 其中,${spring.version}和${quartz.version}分别为Spring框架和Quartz的版本号。 2. 创建定时任务类 创建一个类,实现org.quartz.Job接口,该接口只有一个方法execute(JobExecutionContext context),用来执行定时任务。 ``` public class MyJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 定时任务执行的逻辑代码 } } ``` 3. 配置定时任务 在Spring配置文件中配置CronTriggerBean,同时指定定时任务类和Cron表达式。 ``` <bean id="myJob" class="com.example.MyJob" /> <bean id="myCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="myJob" /> <property name="cronExpression" value="0 0/1 * * * ?" /> </bean> ``` 其中,myJob为定时任务类的Bean ID,myCronTrigger为CronTriggerBean的Bean ID,cronExpression为Cron表达式,表示每分钟执行一次任务。 4. 配置SchedulerFactoryBean 最后,在Spring配置文件中配置SchedulerFactoryBean,将CronTriggerBean添加到调度器中。 ``` <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="myCronTrigger" /> </list> </property> </bean> ``` 至此,基于Cron表达式的定时任务配置完成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值