Spring —— 使用Aop管理定时任务是否执行

问题

项目中往往有很多定时任务,在本地执行时,定时任务的日志混杂在一起,不好分辨,如何方便快速的管理定时任务呢?

解决

使用Aop在定时任务执行前进行切入,根据配置文件判断这个定时任务是否要执行,决定继续执行或直接退出此任务。

步骤

1、引入Spring的Aop依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <scope>provided</scope>
        </dependency>

2、定时任务权限配置

aaa:
  routes:
    - className: '这是某个定时任务的类名'
      run: 'true'

3、定义切面

@Aspect
@Slf4j
@Configuration
//读取配置文件
@ConfigurationProperties("aaa")
public class ScheduleAop {

    @Setter
    private List<Map<String, String>> routes;

    //切入点为第四步中配置的注解
    @Around("@annotation(xxx.EnableScheduleMethod)")
    public Object doAround(ProceedingJoinPoint joinPoint)  throws Throwable {
        log.debug("=====SysLogAspect 环绕通知开始=====");
        log.debug("获取定时任务类名{}", joinPoint.getTarget().getClass().getName());
        log.debug("获取定时任务方法名{}", joinPoint.getSignature().getName());
        log.debug("定时任务的target{}", joinPoint.getTarget());
        String thisClassname = joinPoint.getTarget().getClass().getName();

        //获取这个定时任务名对应的权限
        for (Map thisRoute : routes) {
            if (thisRoute.get("className").equals(thisClassname) && "true".equals(thisRoute.get("run"))) {
                log.debug("执行");
                joinPoint.proceed();
            } else {
                log.debug("未执行");
            }
        }
        log.debug("=====SysLogAspect 环绕通知结束=====");
        return joinPoint;
    }

 
}

4、定义注解

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableScheduleMethod {
}

优化

一、省去自定义注解

去掉自定义注解,直接切到定时任务的@Scheduled注解上。

@Around("@annotation(org.springframework.scheduling.annotation.Scheduled)")

二 、解决多人同时本地启动的问题

权限配置时不采用true、false。采用serverName。

利用每个人的maven中settings.xml中的serverName不同,取得当前本地运行的serverName,并与配置文件中的相比较,如果一致,则运行该定时任务。

最终代码

配置文件

schedule:
  routes:
    包名.类名.方法名: 需要运行的serverName

Aop代码

@Aspect
@Slf4j
@Configuration
//只在dev本地环境生效
@Profile("dev")
public class ScheduleAop {

	//注入serverName
    @Setter
    @Value("${xxx.xx}")
    private String serviceName;

    @Setter
    private Map<String, String> routes;

    //切入@Scheduled注解
    @Around("@annotation(org.springframework.scheduling.annotation.Scheduled)")
    public Object doAround(ProceedingJoinPoint joinPoint) {
        String thisClassname = joinPoint.getTarget().getClass().getName();
        String funcName = joinPoint.getSignature().getName();
        String totalName = thisClassname + '.' + funcName;
        String serverNames = routes.get(totalName);
        if (serverNames != null && serverNames.length() > 0) {
            Arrays.stream(serviceName.split(",")).forEach(
                    thisName -> {
                        if (serviceName.equals(thisName)) {
                            try {
                                joinPoint.proceed();
                            } catch (Throwable throwable) {
                                throwable.printStackTrace();
                            }
                        }
                    }
            );
        }
        return null;
    }
}

猜你喜欢

转载自blog.csdn.net/xue_xiaofei/article/details/112547964