Java 设计模式 --- Template 模式 Java Template 模式 Java 模板设计模式

2023-05-16

        Java 设计模式 --- Template 模式 Java Template 模式 Java 模板设计模式

一、概述

        模板设计模式: 父类定义通用抽象的功能方法,子类负责具体的实现。 本文将以一个通用的定时任务,处理模式,来讲解java 模板设计模式。

假设定时任务,要实现以下功能:

  1. 开关 --- 随时可以关闭
  2. 锁资源 --- 避免多实例重复执行
  3. 任务执行,时间记录
  4. 任务处理
  5. 资源释放

        大致的代码如下:


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.springframework.scheduling.annotation.Scheduled;

/**
 * Description: 通用任务处理
 * @author wu
 * @version 1.0
 * @date 2023/3/26 21:16
 */
@Slf4j
public class GeneralTaskTest {

    /**
     * 分布式锁 , 默认: true
     */
    private boolean lock = true;

    /**
     * 启用 定时任务标记 , 默认: true
     */
    private boolean enable = true;

    @Scheduled(cron = "0/10 * * * * ?")
    public void task(){
        // 1、任务开关
        // apollo 配置 / 数据库配置等
        if(!enable){
            log.info("任务没有打开");
            return;
        }
        // 获取锁 --- redis , zk 等
        // 2、分布式锁 --- 避免多实例执行
        if(!lock){
            log.info("该实例,没有获取到锁");
            return;
        }

        // 3、执行逻辑
        log.info("开始执行~ ");
        final StopWatch stopWatch = StopWatch.createStarted();

        try {
            System.out.println(" 执行定时任务处理逻辑~");
            // 测试异常
            // int i = 1/0;
        }catch (Exception e){
            // 4、异常处理
            log.error("task execute failure , {}", ExceptionUtils.getStackTrace(e));
        }finally {
            // 5、资源关闭
            // 释放锁资源
            stopWatch.stop();
            log.info("任务执行结束,耗时:{} ms",stopWatch.getTime());
        }

    }

}

二、思路设计

        1、 创建 BaseTaskTemplate 类

        有2个属性, enbale 和lock ,分别标记 开关和锁 , 提供 getter / setter 方法,用于子类处理锁标记。

/**
 * 分布式锁 , 默认: true
 */
private boolean lock = true;

/**
 * 启用 定时任务标记 , 默认: true
 */
private boolean enable = true;


        2、核心方法: taskExecute 任务执行类 如下

  • beforeExec : 前置处理,用于获取锁 , 开关字段处理
  • exec(): 业务逻辑处理
  • afterExec(): 资源释放 等
 public void taskExecute(){
        beforeExec();
        if(!lock || !enable){
            log.info(this.getClass().getName() + " , 没有获取到锁,或者定时任务没有开启 ~ lock={} , enable={}", lock, enable);
            return;
        }
        log.info(this.getClass().getName() +" {} ,任务开始执行 -- "+ new Date().getTime());
        final StopWatch stopWatch = StopWatch.createStarted();
        try {
            exec();
        } catch (Exception e) {
          log.error(this.getClass().getName() + ",定时任务执行出错, cause by : {}", ExceptionUtils.getStackTrace(e));
//            throw  e;  // throw e
        } finally {
            afterExec();
            stopWatch.stop();
            log.info("finally 程序执行结束,耗时:{} ms ", stopWatch.getTime());
        }
        log.info("任务执行结束~ over ...");
    }
    

三、代码实现

        1、BaseTaskTemplate ,通用任务模板,代码如下:


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.time.StopWatch;

import java.util.Date;

/**
 * Description: BaseTaskTemplate , 通用定时任务执行模板
 * @author w
 * @version 1.0
 * @date 2023/3/9 15:20
 * @remarks: 该任务迁移到 scheduler 分支
 * @see
 */
@Slf4j
public class BaseTaskTemplate {

    /**
     * 分布式锁 , 默认: true
     */
    private boolean lock = true;

    /**
     * 启用 定时任务标记 , 默认: true
     */
    private boolean enable = true;

    public void taskExecute(){
        beforeExec();
        if(!lock || !enable){
            log.info(this.getClass().getName() + " , 没有获取到锁,或者定时任务没有开启 ~ lock={} , enable={}", lock, enable);
            return;
        }
        log.info(this.getClass().getName() +" {} ,任务开始执行 -- "+ new Date().getTime());
        final StopWatch stopWatch = StopWatch.createStarted();
        try {
            exec();
        } catch (Exception e) {
          log.error(this.getClass().getName() + ",定时任务执行出错, cause by : {}", ExceptionUtils.getStackTrace(e));
//            throw  e;  // throw e
        } finally {
            afterExec();
            stopWatch.stop();
            log.info("finally 程序执行结束,耗时:{} ms ", stopWatch.getTime());
        }
        log.info("任务执行结束~ over ...");
    }

    protected void afterExec() {
    }

    protected void beforeExec() {
    }

    protected void exec() throws Exception {
    }

    public boolean isLock() {
        return lock;
    }

    public void setLock(boolean lock) {
        this.lock = lock;
    }

    public boolean isEnable() {
        return enable;
    }

    public void setEnable(boolean enable) {
        this.enable = enable;
    }
}

        2、创建 UserTaskTemplate 类

        继承 BaseTaskTemplate 重写 exec 方法,写具体业务处理逻辑, 创建 task 方法, 配置对应的 定时策略,在方法体中使用 super.taskExecute(); 调用任务处理,完整代码如下


import com.runcode.springboottourist.template.BaseTaskTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * Description: UserTaskTemplate
 * @author w
 * @version 1.0
 * @date 2023/3/10 14:41
 */
@Slf4j
@Component
public class UserTaskTemplate extends BaseTaskTemplate {

    @Scheduled(cron = "0/10 * * * * ?")
    public void task (){
        log.info("UserTaskTemplate === ");
        super.taskExecute();
    }

    @Override
    protected void exec() throws Exception {
        TimeUnit.SECONDS.sleep(1);
        log.info(" 执行定时任务逻辑处理 ~ ");
    }

    @Value("${UserTaskTemplate.enable:true}")
    @Override
    public void setEnable(boolean enable) {
        super.setEnable(enable);
    }

    @Override
    protected void beforeExec() {
        log.warn("beforeExec ===>>>");
        // 获取锁 --- redis.getLock
    }

    @Override
    protected void afterExec() {
        log.warn("beforeExec  ===>>>");
        // 释放锁 --- redis.releaseLock
    }
}

        3、测试结果如下:

2023-03-26 21:38:30.002  INFO 119920 --- [uler pool===>>4] c.r.s.task.UserTaskTemplate              : UserTaskTemplate === 
2023-03-26 21:38:30.002  WARN 119920 --- [uler pool===>>4] c.r.s.task.UserTaskTemplate              : beforeExec ===>>>
2023-03-26 21:38:30.002  INFO 119920 --- [uler pool===>>4] c.r.s.template.BaseTaskTemplate          : com.runcode.springboottourist.task.UserTaskTemplate {} ,任务开始执行 -- 1679837910002
2023-03-26 21:38:31.014  INFO 119920 --- [uler pool===>>4] c.r.s.task.UserTaskTemplate              :  执行定时任务逻辑处理 ~ 
2023-03-26 21:38:31.014  WARN 119920 --- [uler pool===>>4] c.r.s.task.UserTaskTemplate              : afterExec  ===>>>
2023-03-26 21:38:31.014  INFO 119920 --- [uler pool===>>4] c.r.s.template.BaseTaskTemplate          : finally 程序执行结束,耗时:1011 ms 
2023-03-26 21:38:31.014  INFO 119920 --- [uler pool===>>4] c.r.s.template.BaseTaskTemplate          : 任务执行结束~ over ...

四、总结

        1、 若又有一个任务需要执行,直接继承 BaseTaskTemplate 类即可,重写 exec 方法;

  • 需要配置锁资源 , 重写 beforeExec 和 afterExec 方法 ;
  • 需要配置 开关 , 重写 setEnable 方法,加上 @Value 注解即可

        2、beforeExec 、afterExec 方法,是参考 线程池 ThreadPoolExecutor 的 实现, 如下:

参考资料:

Spring @Value 赋值

Java 设计模式 --- Builder模式 Java Builder 模式

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 设计模式 --- Template 模式 Java Template 模式 Java 模板设计模式 的相关文章

随机推荐