Java 设计模式 --- Template 模式 Java Template 模式 Java 模板设计模式
一、概述
模板设计模式: 父类定义通用抽象的功能方法,子类负责具体的实现。 本文将以一个通用的定时任务,处理模式,来讲解java 模板设计模式。
假设定时任务,要实现以下功能:
- 开关 --- 随时可以关闭
- 锁资源 --- 避免多实例重复执行
- 任务执行,时间记录
- 任务处理
- 资源释放
大致的代码如下:
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(使用前将#替换为@)