AsgcCompiler优化,支持保存生成的源码、class文件。

This commit is contained in:
aoshiguchen
2022-09-10 13:30:50 +08:00
parent b5bcaeddc0
commit d7e24b49b8
5 changed files with 121 additions and 10 deletions
@@ -24,6 +24,7 @@ package fun.asgc.neutrino.core.aop.compiler;
import com.google.common.collect.Lists;
import fun.asgc.neutrino.core.base.GlobalConfig;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.core.util.FileUtil;
import fun.asgc.neutrino.core.util.SystemUtil;
import lombok.extern.slf4j.Slf4j;
@@ -78,6 +79,9 @@ public class AsgcCompiler {
}
public void addClasspath(String classpath) {
if (this.classpathList.contains(classpath)) {
return;
}
this.classpathList.add(classpath);
}
@@ -128,7 +132,15 @@ public class AsgcCompiler {
public Class<?> compile(String pkg, String className, String sourceCode) throws ClassNotFoundException {
log.info("options:" + getOptions());
JavaFileManager javaFileManager = new DynamicJavaFileManager(standardJavaFileManager, dynamicClassLoader);
Boolean result = javaCompiler.getTask(null, javaFileManager, collector, getOptions(), null, Lists.newArrayList(new StringSource(className, sourceCode))).call();
Iterable<? extends JavaFileObject> compilationUnits = Lists.newArrayList(new StringSource(className, sourceCode));
if (GlobalConfig.isSaveGeneratorCode()) {
javaFileManager = standardJavaFileManager;
File file = FileUtil.save(GlobalConfig.getGeneratorCodeSavePath() + pkg.replaceAll("\\.", "/"), className + ".java", sourceCode);
compilationUnits = standardJavaFileManager.getJavaFileObjects(file);
addClasspath(GlobalConfig.getGeneratorCodeSavePath());
}
Boolean result = javaCompiler.getTask(null, javaFileManager, collector, getOptions(), null, compilationUnits).call();
if (!result || collector.getDiagnostics().size() > 0) {
if (!result || collector.getDiagnostics().size() > 0) {
for (Diagnostic<? extends JavaFileObject> diagnostic : collector.getDiagnostics()) {
@@ -21,11 +21,22 @@
*/
package fun.asgc.neutrino.core.aop.compiler;
import fun.asgc.neutrino.core.base.GlobalConfig;
import fun.asgc.neutrino.core.util.ArrayUtil;
import fun.asgc.neutrino.core.util.ClassUtil;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.core.util.FileUtil;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
*
@@ -35,6 +46,7 @@ import java.util.*;
public class DynamicClassLoader extends ClassLoader {
private final Map<String, MemoryByteCode> byteCodes = new HashMap<>();
private AsgcCompiler compiler;
private Map<String, Class<?>> classMap = new HashMap<>();
public DynamicClassLoader(ClassLoader classLoader) {
super(classLoader);
@@ -51,6 +63,9 @@ public class DynamicClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (classMap.containsKey(name)) {
return classMap.get(name);
}
MemoryByteCode byteCode = byteCodes.get(name);
if (null != byteCode) {
return super.defineClass(name, byteCode.getByteCode(), 0, byteCode.getByteCode().length);
@@ -78,7 +93,7 @@ public class DynamicClassLoader extends ClassLoader {
if (path.endsWith(".jar")) {
url = new URL("jar:file:" + path + "!/");
}
Set<Class<?>> classSet = ClassUtil.scan(packageName, url);
Set<Class<?>> classSet = scan(packageName, url);
if (CollectionUtil.isEmpty(classSet)) {
continue;
}
@@ -93,6 +108,69 @@ public class DynamicClassLoader extends ClassLoader {
return null;
}
public Set<Class<?>> scan(String packageName, URL url) throws IOException, ClassNotFoundException, URISyntaxException {
Set<Class<?>> result = new HashSet<>();
if (null == url) {
return result;
}
String packagePath = packageName.replace(".", "/");
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url}, Thread.currentThread().getContextClassLoader());
String protocol = url.getProtocol();
if ("jar".equals(protocol)) {
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
JarFile jarFile = jarURLConnection.getJarFile();
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
String name = jarEntry.getName();
int index = name.indexOf(packagePath);
if (index != -1 && name.endsWith(".class")) {
String replace = name.substring(index, name.length() - 6).replace("/", ".");
Class clazz = urlClassLoader.loadClass(replace);
result.add(clazz);
}
}
} else if ("file".endsWith(protocol)) {
String path = url.getPath();
String targetPath = path + "/" + packagePath;
addClasses(targetPath, result, packageName);
}
return result;
}
private synchronized void addClasses(String path, Set<Class<?>> classes, String packageName) throws ClassNotFoundException, URISyntaxException {
File[] files = new File(path).listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
}
});
if (ArrayUtil.isEmpty(files)) {
return;
}
for (File file : files) {
String fileName = file.getName();
if (file.isFile()) {
String className = fileName.substring(0, fileName.lastIndexOf("."));
String fullClassName = packageName + "." + className;
Class clazz = null;
if (path.startsWith(GlobalConfig.getGeneratorCodeSavePath())) {
byte[] byteCode = FileUtil.readBytes(file);
clazz = super.defineClass(fullClassName, byteCode, 0, byteCode.length);
this.classMap.put(fullClassName, clazz);
} else {
clazz = Thread.currentThread().getContextClassLoader().loadClass(fullClassName);
}
classes.add(clazz);
} else {
String subPackagePath = path + "/" + fileName;
String subPackageName = packageName + "." + fileName;
addClasses(subPackagePath, classes, subPackageName);
}
}
}
public Map<String, Class<?>> getClasses() throws ClassNotFoundException {
Map<String, Class<?>> classes = new HashMap<>();
for (MemoryByteCode byteCode : byteCodes.values()) {
@@ -39,6 +39,7 @@ public class MemoryByteCode extends SimpleJavaFileObject {
private static final String CLASS_FILE_SUFFIX = ".class";
private ByteArrayOutputStream byteArrayOutputStream;
private byte[] byteCode;
public MemoryByteCode(String className) {
super(URI.create("byte:///" + className.replace(PKG_SEPARATOR, DIR_SEPARATOR)
@@ -51,6 +52,12 @@ public class MemoryByteCode extends SimpleJavaFileObject {
this.byteArrayOutputStream = byteArrayOutputStream;
}
public MemoryByteCode(String className, byte[] byteCode)
throws URISyntaxException {
this(className);
this.byteCode = byteCode;
}
@Override
public OutputStream openOutputStream() throws IOException {
if (byteArrayOutputStream == null) {
@@ -60,7 +67,7 @@ public class MemoryByteCode extends SimpleJavaFileObject {
}
public byte[] getByteCode() {
return byteArrayOutputStream.toByteArray();
return null == byteCode ? byteArrayOutputStream.toByteArray() : byteCode;
}
public String getClassName() {
@@ -111,18 +111,30 @@ public class FileUtil {
*/
public static byte[] readBytes(String path) {
try (InputStream in = getInputStream(path)){
byte[] bytes = new byte[1024];
int length = 0;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((length = in.read(bytes)) != -1) {
baos.write(bytes, 0, length);
}
return baos.toByteArray();
return readBytes(in);
} catch (Exception e) {
return null;
}
}
public static byte[] readBytes(File file) {
try (InputStream in = new FileInputStream(file)){
return readBytes(in);
} catch (Exception e) {
return null;
}
}
public static byte[] readBytes(InputStream in) throws IOException {
byte[] bytes = new byte[1024];
int length = 0;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((length = in.read(bytes)) != -1) {
baos.write(bytes, 0, length);
}
return baos.toByteArray();
}
public static void write(String path, String content) {
// try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(path), StandardCharsets.UTF_8)){
// writer.write(content);
@@ -24,6 +24,7 @@ package fun.asgc.neutrino.proxy.server;
import fun.asgc.neutrino.core.annotation.EnableJob;
import fun.asgc.neutrino.core.annotation.NeutrinoApplication;
import fun.asgc.neutrino.core.base.GlobalConfig;
import fun.asgc.neutrino.core.context.NeutrinoLauncher;
/**
@@ -36,6 +37,7 @@ import fun.asgc.neutrino.core.context.NeutrinoLauncher;
public class ProxyServer {
public static void main(String[] args) {
GlobalConfig.setIsSaveGeneratorCode(true);
NeutrinoLauncher.run(ProxyServer.class, args).sync();
}