Java加载 Grovy 类实现类的自动切换
Grovy 代码
import java.util.function.Function
class DynamicService implements Function<String, String> {
void accept(String t) {
println "acceptFunction"
}
@Override
String apply(String o) {
print("Function")
return "Ok";
}
}
Grovy 动态加载代码
import groovy.lang.GroovyClassLoader;
import org.codehaus.groovy.control.CompilationFailedException;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.attribute.FileTime;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.*;
import java.util.function.Function;
public class GroovyDynamicCompiler1 {
// 缓存结构:文件路径 -> (类对象, 最后修改时间)
private static final Map<String, CacheEntry> CLASS_CACHE = new ConcurrentHashMap<>();
// 定时更新线程池
private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
// 缓存有效期(30分钟)
private static final Duration CACHE_DURATION = Duration.ofMinutes(30);
static {
// 启动定时清理任务
SCHEDULER.scheduleAtFixedRate(() ->
CLASS_CACHE.entrySet().removeIf(entry ->
entry.getValue().isExpired() || !entry.getValue().isValid()
), 5, 5, TimeUnit.MINUTES);
// 关闭钩子
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
SCHEDULER.shutdown();
CLASS_CACHE.clear();
}));
}
public static void main(String[] args) throws Exception {
// 填写文件地址
Class<?> groovyClass = compileGroovyFile("");
Object instance = groovyClass.newInstance();
((Function) instance).apply("s");
}
public static Class<?> compileGroovyFile(final String filePath) {
// 1. 验证路径是否合法
String fileName = validateFilePathAndGetFileName(filePath);
// 2.如果函数返回 null,则删除映射(如果最初不存在,则保持不存在)。
return CLASS_CACHE.compute(fileName, (name, oldEntry) -> {
try {
File file = new File(filePath);
FileTime lastModified = Files.getLastModifiedTime(file.toPath());
// 需要重新编译的情况:缓存不存在/文件被修改/ 缓存过期机制
if (oldEntry == null || oldEntry.isExpired() || lastModified.compareTo(oldEntry.lastModified) != 0) {
//
try (GroovyClassLoader loader = new GroovyClassLoader()) {
Class<?> clazz = loader.parseClass(file);
CacheEntry newEntry = new CacheEntry(clazz, lastModified);
return newEntry;
}
}
return oldEntry;
} catch (CompilationFailedException | IOException e) {
// 抛异常 还是标记错误
throw new RuntimeException("Groovy编译失败: " + e.getMessage(),e);
}
}).clazz;
}
private static String validateFilePathAndGetFileName(String filePath) {
// 缓存穿透防护
if (filePath == null || filePath.trim().isEmpty()) {
throw new IllegalArgumentException("文件路径不能为空");
}
File file = new File(filePath);
if (!file.exists() || !file.isFile()) {
throw new IllegalArgumentException("无效文件路径: " + filePath);
}
return file.getName();
}
// 缓存条目结构
private static class CacheEntry {
final Class<?> clazz;
final FileTime lastModified;
final long createTime;
CacheEntry(Class<?> clazz, FileTime lastModified) {
this.clazz = clazz;
this.lastModified = lastModified;
this.createTime = System.currentTimeMillis();
}
boolean isExpired() {
return System.currentTimeMillis() - createTime > CACHE_DURATION.toMillis();
}
boolean isValid() {
try {
return clazz != null && clazz.getClassLoader() != null;
} catch (Exception e) {
return false;
}
}
}
}