需求:导出项目中使用任务调度的类,方法,注释,以及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;
}
}