通过反射获取当前项目哪些方法使用了任务调度(包含方法的注释)

需求:导出项目中使用任务调度的类,方法,注释,以及corn表达式(如果有)

import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.RootDoc;
import org.quartz.DisallowConcurrentExecution;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test {
    public static void main(String[] args) {
        // 一个项目里面有多个服务,该test是一个main方法,所有只能拷贝到每个服务下(Application同级)执行
        String[] packageName = Test.class.getPackage().getName().split("\\.");
        String serviceName = packageName[packageName.length - 1];
        // 指定java文件路径
        String path = "F:\\YZR\\xxx\\" + serviceName;
        File file = new File(path);
        // 递归获取java文件
        listFile(file, "");
        Class clazz = null;
        TestEntity testEntity = null;
        List listEntity = new ArrayList<>();
        for (String className : classList) {
            try {
                clazz = Class.forName(className);
            } catch (ClassNotFoundException e) {
                // 因为是循环的文件,所以会出现文件存在,但是文件里面所有代码是注释掉的情况,故跳过
                continue;
            }
            // Scheduled实现调度都有EnableScheduling注解
            boolean annotationPresent = clazz.isAnnotationPresent(EnableScheduling.class);
            // quartz实现调度都有DisallowConcurrentExecution注解(避免并发调度)
            boolean disallowConcurrentExecution = clazz.isAnnotationPresent(DisallowConcurrentExecution.class);
            if (annotationPresent) {
                dealMethod(serviceName, clazz, listEntity, className, Scheduled.class);
            } else if (disallowConcurrentExecution) {
                dealMethod(serviceName, clazz, listEntity, className, Bean.class);
            }
        }
        for (TestEntity entity : listEntity) {
            System.out.println(entity.getServiceName() + "!" + entity.getClassFullName() + "!" + entity.getMethodName() + "!" + entity.getCornExpression() + "!" + entity.getMemo());
        }
    }

    /**
     * 处理含有任务调度的方法
     *
     * @param serviceName     服务名
     * @param clazz           类
     * @param listEntity      任务调度相关信息的实体list
     * @param className       全类名
     * @param classMethodAnno 打在方法上的注解class(有的是用Scheduled,有的是用quartz,quartz是注入的bean,当然具体执行是调用的覆写的execute()方法)
     */
    private static void dealMethod(String serviceName, Class clazz, List listEntity, String className, Class classMethodAnno) {
        TestEntity testEntity;
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            boolean flag = method.isAnnotationPresent(classMethodAnno);
            if (flag) {
                testEntity = new TestEntity();
                testEntity.setServiceName(serviceName);
                testEntity.setClassFullName(className);
                testEntity.setMethodName(method.getName());
                if (Scheduled.class.equals(classMethodAnno)) {
                    testEntity.setCornExpression(method.getAnnotation(Scheduled.class).cron());
                } else {
                    // quartz的corn表达式是写在方法内的,没在注解上,故这里置空
                    testEntity.setCornExpression(null);
                }
                // 根据全类名获取该java文件的全路径
                String filePathString = classMap.get(className);
                String methodComment = null;
                try {
                    // 获取方法注释
                    methodComment = getCommentText(filePathString, method.getName());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                testEntity.setMemo(methodComment);
                listEntity.add(testEntity);
            }
        }
    }

    // 全限定类名List
    static List classList = new ArrayList<>();
    // 全限定类名和全路径名称Map
    static Map classMap = new HashMap<>();

    /**
     * 递归目录
     *
     * @param dir     文件路径
     * @param pathStr 递归路径
     */
    public static void listFile(File dir, String pathStr) {
        //列出所有的子文件(夹)
        File[] files = dir.listFiles();
        for (File file : files) {
            if (file.isFile()) {
                //如果是文件,且是java文件
                if (file.getName().endsWith(".java")) {
                    String[] str = (pathStr + File.separator + file.getName().replaceAll(".java", "")).split(File.separator + File.separator + "src" + File.separator + File.separator + "main" + File.separator + File.separator + "java" + File.separator + File.separator);
                    if (str.length == 2) {
                        String classFullName = str[1].replaceAll(File.separator + File.separator, ".");
                        // 存储全类名
                        classList.add(classFullName);
                        // 存储全类名和类文件的绝对路径方便读取注释
                        classMap.put(classFullName, pathStr + File.separator + file.getName());
                    }
                }
            } else if (file.isDirectory()) {
                //递归遍历
                listFile(file, file.getPath());
            }
        }
    }

    // 定义注释根
    private static RootDoc root;

    // 注释工具类
    public static class Doclet {

        public static boolean start(RootDoc root) {
            Test.root = root;
            return true;
        }
    }

    // 获取方法注释
    public static String getComments(String methodName) {
        ClassDoc[] classes = root.classes();
        String str = "";
        for (int i = 0; i < classes.length; ++i) {
            for (MethodDoc method : classes[i].methods()) {
                if (methodName.equals(method.name())) {
                    str = method.getRawCommentText().replaceAll("\r", "").replaceAll("\n", "");
                }
            }
        }
        // 此处我需要null方便导入Excel
        if ("".equals(str.trim())) {
            str = null;
        }
        return str;
    }

    /**
     * @param filePathString java文件全路径
     * @param methodName     需要获取注释的方法名
     */
    public static String getCommentText(String filePathString, String methodName) {
        com.sun.tools.javadoc.Main.execute(new String[]{
                // 指定自己的docLet类名
                "-doclet", Test.Doclet.class.getName(),
                // 指定源码文件的编码格式
                "-encoding", "utf-8",
                // 获取单个代码文件的javadoc
                filePathString});
        return getComments(methodName);
    }
}

/**
 * 任务调度相关信息的实体
 */
class TestEntity {
    // 服务名
    private String serviceName;
    // 类全限定名
    private String classFullName;
    // 方法名
    private String methodName;
    // corn表达式
    private String cornExpression;
    // 注释
    private String memo;

    public String getServiceName() {
        return serviceName;
    }

    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }

    public String getClassFullName() {
        return classFullName;
    }

    public void setClassFullName(String classFullName) {
        this.classFullName = classFullName;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public String getCornExpression() {
        return cornExpression;
    }

    public void setCornExpression(String cornExpression) {
        this.cornExpression = cornExpression;
    }

    public String getMemo() {
        return memo;
    }

    public void setMemo(String memo) {
        this.memo = memo;
    }
}

你可能感兴趣的:(通过反射获取当前项目哪些方法使用了任务调度(包含方法的注释))