自动重启加载生成的代码类

This commit is contained in:
ruying408
2024-07-14 22:12:51 +08:00
parent 14f9897569
commit 2d5b24f72d
7 changed files with 187 additions and 61 deletions

View File

@@ -1,11 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="AdditionalModuleElements">
<content url="file://$MODULE_DIR$" dumb="true">
<sourceFolder url="file://$MODULE_DIR$/target/generated-sources/annotations/src/main/java" isTestSource="false" />
</content>
<content url="file://$MODULE_DIR$" dumb="true">
<sourceFolder url="file://$MODULE_DIR$/target/generated-sources/annotations" isTestSource="false" />
</content>
</content>
</component>
</module>

View File

@@ -1,17 +1,22 @@
package com.cool;
import com.cool.core.util.PathUtils;
import com.tangzc.autotable.springboot.EnableAutoTable;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;
import com.tangzc.autotable.springboot.EnableAutoTable;
/**
* CoolApplication - 应用程序的主类
* 该类配置并运行应用程序。
*/
@Slf4j
@EnableAutoTable // 开启自动建表
@EnableAsync // 开启异步处理
@EnableCaching // 开启缓存
@@ -19,7 +24,51 @@ import com.tangzc.autotable.springboot.EnableAutoTable;
@MapperScan("com.cool.modules.*.mapper") // 扫描指定包中的MyBatis映射器
public class CoolApplication {
private static volatile ConfigurableApplicationContext context;
private static ClassLoader mainThreadClassLoader;
public static void main(String[] args) {
SpringApplication.run(CoolApplication.class, args);
mainThreadClassLoader = Thread.currentThread().getContextClassLoader();
context = SpringApplication.run(CoolApplication.class, args);
}
/**
* 通过关闭当前上下文并启动新上下文来重启应用程序。
*/
public static void restart(List<String> javaPathList) {
// 从当前上下文获取应用程序参数
ApplicationArguments args = context.getBean(ApplicationArguments.class);
// 创建新线程来重启应用程序
Thread thread = new Thread(() -> {
try {
// 关闭当前应用程序上下文
context.close();
// 等待上下文完全关闭
while (context.isActive()) {
Thread.sleep(100);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 加载动态生成的代码
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
javaPathList.forEach(javaPath -> {
try {
classLoader.loadClass(PathUtils.getClassName(javaPath));
} catch (ClassNotFoundException e) {
log.error("loadClassErr {}", javaPath, e);
}
});
// 使用相同的参数运行Spring Boot应用程序并设置上下文
context = SpringApplication.run(CoolApplication.class, args.getSourceArgs());
});
// 设置线程的上下文类加载器
thread.setContextClassLoader(mainThreadClassLoader);
// 确保线程不是守护线程
thread.setDaemon(false);
// 启动线程
thread.start();
}
}

View File

@@ -11,13 +11,11 @@ import com.cool.core.exception.CoolPreconditions;
import com.cool.core.file.UpLoadModeType;
import com.cool.modules.plugin.entity.PluginInfoEntity;
import jakarta.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
@@ -47,16 +45,16 @@ public class LocalFileUploadStrategy implements FileUploadStrategy {
String date = DateUtil.format(new Date(),
DatePattern.PURE_DATE_PATTERN);
String relativePath =
"/" + localFileProperties.getUploadPath() + "/" + date;
File.separator + localFileProperties.getUploadPath() + File.separator + date;
FileUtil.mkdir(filePath + relativePath);
for (MultipartFile file : files) {
// 保存文件
String fileName = StrUtil.uuid().replaceAll("-", "") + getExtensionName(
Objects.requireNonNull(file.getOriginalFilename()));
file.transferTo(new File(filePath + "/" + relativePath
+ "/" + fileName));
fileUrls.add(baseUrl + "/" + date + "/" + fileName);
file.transferTo(new File(filePath + File.separator + relativePath
+ File.separator + fileName));
fileUrls.add(baseUrl + File.separator + date + File.separator + fileName);
}
if (fileUrls.size() == 1) {
return fileUrls.get(0);

View File

@@ -94,7 +94,7 @@ public class CoolPluginService {
String pathStr = pluginPath;
if (!PathUtils.isAbsolutePath(pluginPath)) {
// 相对路径
pathStr = System.getProperty("user.dir") + "/" + pluginPath;
pathStr = System.getProperty("user.dir") + File.separator + pluginPath;
}
// 将路径字符串转换为 Path 对象
Path path = Paths.get(pathStr);
@@ -104,7 +104,7 @@ public class CoolPluginService {
Files.createDirectories(path);
}
fileName =
path + "/" + System.currentTimeMillis() + "_" + file.getOriginalFilename() + ".jar";
path + File.separator + System.currentTimeMillis() + "_" + file.getOriginalFilename() + ".jar";
jarFile = new File(fileName);
file.transferTo(jarFile);
// 加载jar

View File

@@ -3,13 +3,14 @@ package com.cool.core.util;
import cn.hutool.core.io.FileUtil;
import com.mybatisflex.processor.MybatisFlexProcessor;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import javax.annotation.processing.Processor;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
public class CompilerUtils {
@@ -21,66 +22,131 @@ public class CompilerUtils {
FileUtil.del(filePathStr);
File file = FileUtil.touch(filePathStr);
FileUtil.appendString(content, file, StandardCharsets.UTF_8.name());
compileAndSave(filePathStr);
}
public static void createMapper(String actModulePath, String fileName, String mapper) {
String pathStr = actModulePath + "/mapper/";
public static String createMapper(String actModulePath, String fileName, String mapper) {
String pathStr = actModulePath + File.separator + "mapper" + File.separator;
String filePathStr = pathStr + fileName + "Mapper.java";
createFile(mapper, filePathStr);
return filePathStr;
}
public static void createServiceImpl(String actModulePath, String fileName,
public static String createServiceImpl(String actModulePath, String fileName,
String serviceImpl) {
String pathStr = actModulePath + "/service/impl/";
String pathStr = actModulePath + File.separator + "service" + File.separator + "impl" + File.separator;
String filePathStr = pathStr + fileName + "ServiceImpl.java";
createFile(serviceImpl, filePathStr);
return filePathStr;
}
public static void createService(String actModulePath, String fileName, String service) {
String pathStr = actModulePath + "/service/";
public static String createService(String actModulePath, String fileName, String service) {
String pathStr = actModulePath + File.separator + "service" + File.separator;
String filePathStr = pathStr + fileName + "Service.java";
createFile(service, filePathStr);
return filePathStr;
}
public static String createEntity(String actModulePath, String fileName, String entity) {
String pathStr = actModulePath + "/entity/";
String pathStr = actModulePath + File.separator + "entity" + File.separator;
String filePathStr = pathStr + fileName + "Entity.java";
createFile(entity, filePathStr);
return filePathStr;
}
public static void createController(String actModulePath, String fileName, String controller) {
String pathStr = actModulePath + "/controller/admin/";
public static String createController(String actModulePath, String fileName, String controller) {
String pathStr = actModulePath + File.separator + "controller" + File.separator + "admin" + File.separator;
String filePathStr = pathStr + "Admin" + fileName + "Controller.java";
createFile(controller, filePathStr);
return filePathStr;
}
public static String createModule(String modulesPath, String module) {
String pathStr = modulesPath + "/" + module;
String pathStr = modulesPath + File.separator + module;
PathUtils.noExistsMk(pathStr);
return pathStr;
}
public static void compilerEntityTableDef(String path) {
// JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
//
// Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(
// path);
//
// // 设置注解处理器
// Iterable<? extends Processor> processors = Arrays.asList(new MybatisFlexProcessor());
// // 添加 -proc:only 选项
// List<String> options = Arrays.asList("-proc:only");
// JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options,
// null, compilationUnits);
// task.setProcessors(processors);
//
// boolean success = task.call();
// if (success) {
// System.out.println("Compilation and annotation processing completed successfully.");
// } else {
// System.out.println("Compilation and annotation processing failed.");
// }
public static boolean compileAndSave(String sourceFile) {
// 获取系统 Java 编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// 获取标准文件管理器
try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) {
// 设置编译输出目录
fileManager.setLocation(StandardLocation.CLASS_OUTPUT, List.of(new File("target" + File.separator + "classes")));
// 获取源文件
List<File> javaFiles = List.of(new File(sourceFile));
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(javaFiles);
// 创建编译任务
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, compilationUnits);
// 执行编译任务
return task.call();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
public static void compilerEntityTableDef(String actModulePath, String fileName, String entityPath, List<String> javaPathList) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) {
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(
entityPath);
// // 设置注解处理器
Iterable<? extends Processor> processors = List.of(new MybatisFlexProcessor());
// // 添加 -proc:only 选项
List<String> options = List.of("-proc:only");
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options,
null, compilationUnits);
task.setProcessors(processors);
task.call();
compilationUnits = fileManager.getJavaFileObjects(
javaPathList.toArray(new String[0]));
// 需在entity之后加载
// 设置编译输出目录
fileManager.setLocation(StandardLocation.CLASS_OUTPUT, List.of(new File("target/classes")));
task = compiler.getTask(null, fileManager, null, null, null, compilationUnits);
String pathStr = actModulePath + File.separator + "entity" + File.separator + "table" + File.separator;
String filePathStr = pathStr + fileName + "EntityTableDef.java";
javaPathList.add(1, filePathStr);
boolean success = task.call();
if (success) {
System.out.println("Compilation and annotation processing completed successfully.");
String commPath = PathUtils.getUserDir() + File.separator + "com";
if (countFiles(new File(commPath)) <= 1) {
FileUtil.clean(commPath);
FileUtil.del(commPath);
}
} else {
System.out.println("Compilation and annotation processing failed.");
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static int countFiles(File directory) {
File[] files = directory.listFiles();
if (files == null) {
return 0;
}
int count = 0;
for (File file : files) {
if (file.isFile()) {
count++;
} else if (file.isDirectory()) {
count += countFiles(file);
}
// If more than one file is found, no need to continue counting
if (count > 1) {
break;
}
}
return count;
}
}

View File

@@ -2,6 +2,7 @@ package com.cool.core.util;
import cn.hutool.core.io.file.PathUtil;
import com.cool.CoolApplication;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -17,8 +18,21 @@ public class PathUtils {
}
public static String getModulesPath() {
return getUserDir() + "/src/main/java/" + CoolApplication.class.getPackageName()
.replace(".", "/") + "/modules";
return getUserDir() + File.separator + "src"+ File.separator + "main" + File.separator + "java" + File.separator + CoolApplication.class.getPackageName()
.replace(".", File.separator) + File.separator + "modules";
}
public static String getClassName(String filePath) {
// 定位 "src/main/java" 在路径中的位置
int srcMainJavaIndex = filePath.indexOf("src" + File.separator + "main" + File.separator + "java");
if (srcMainJavaIndex == -1) {
throw new IllegalArgumentException("File path does not contain 'src/main/java'");
}
// 提取 "src/main/java" 之后的路径
// 将文件分隔符替换为包分隔符
return filePath.substring(srcMainJavaIndex + ("src" + File.separator + "main" + File.separator + "java").length() + 1)
.replace(File.separator, ".").replace(".java", "");
}
/**

View File

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONObject;
import com.cool.CoolApplication;
import com.cool.core.base.BaseServiceImpl;
import com.cool.core.base.ModifyEnum;
import com.cool.core.util.CompilerUtils;
@@ -147,24 +148,25 @@ public class BaseSysMenuServiceImpl extends BaseServiceImpl<BaseSysMenuMapper, B
String mapper = (String) params.get("mapper");
String fileName = (String) params.get("fileName");
List<String> javaPathList = new ArrayList<>();
String modulesPath = PathUtils.getModulesPath();
// 创建的模块地址
String actModulePath = CompilerUtils.createModule(modulesPath, module);
// 创建 controller
CompilerUtils.createController(actModulePath, fileName, controller);
// 创建顺序不能调整,类加载的时候需按这个顺序加载,否则类找不到
// 创建 entity
String entityPath = CompilerUtils.createEntity(actModulePath, fileName, entity);
// 创建 service
CompilerUtils.createService(actModulePath, fileName, service);
// 创建 serviceImpl
CompilerUtils.createServiceImpl(actModulePath, fileName, serviceImpl);
javaPathList.add(entityPath);
// 创建 mapper
CompilerUtils.createMapper(actModulePath, fileName, mapper);
// 关闭springboot
System.exit(0);
javaPathList.add(CompilerUtils.createMapper(actModulePath, fileName, mapper));
// 创建 service
javaPathList.add(CompilerUtils.createService(actModulePath, fileName, service));
// 创建 serviceImpl
javaPathList.add(CompilerUtils.createServiceImpl(actModulePath, fileName, serviceImpl));
// 创建 controller
javaPathList.add(CompilerUtils.createController(actModulePath, fileName, controller));
// 构建TableDef
// CompilerUtils.compilerEntityTableDef(entityPath);
CompilerUtils.compilerEntityTableDef(actModulePath, fileName, entityPath, javaPathList);
// 重启
// CoolApplication.restart();
CoolApplication.restart(javaPathList);
}
}