解决jar包启动报错的问题。
This commit is contained in:
+1
-1
@@ -67,7 +67,7 @@ public class InterceptorFactory {
|
||||
() -> {
|
||||
try {
|
||||
Object obj = null;
|
||||
if (GlobalConfig.isIsContainerStartup()) {
|
||||
if (GlobalConfig.isContainerStartup()) {
|
||||
obj = BeanManager.getBean(clazz);
|
||||
}
|
||||
if (null == obj) {
|
||||
|
||||
@@ -82,16 +82,23 @@ public class AsgcProxyFactory implements ProxyFactory {
|
||||
proxyClass.setName(generateClassName(targetType));
|
||||
String sourceCode = AsgcProxyGenerator.getInstance().generator(proxyClass.getName(), targetType, proxyType);
|
||||
proxyClass.setSourceCode(sourceCode);
|
||||
if (GlobalConfig.isIsPrintGeneratorCode()) {
|
||||
if (GlobalConfig.isPrintGeneratorCode()) {
|
||||
log.debug("类:{} 的代理类源码:\n{}", targetType.getName(), sourceCode);
|
||||
}
|
||||
|
||||
compiler.compile(proxyClass);
|
||||
Class<P> retClass = (Class<P>)classLoader.loadProxyClass(proxyClass);
|
||||
Class<P> retClass = compile(proxyClass);
|
||||
P obj = retClass.newInstance();
|
||||
return obj;
|
||||
}
|
||||
|
||||
private <T> Class<T> compile(ProxyClass proxyClass) throws ClassNotFoundException {
|
||||
if (SystemUtil.isStartupFromJar() || GlobalConfig.isSaveGeneratorCode()) {
|
||||
compiler.compileToFile(proxyClass);
|
||||
return (Class<T>)classLoader.loadProxyClass(proxyClass);
|
||||
}
|
||||
compiler.compile(proxyClass);
|
||||
return (Class<T>)classLoader.loadProxyClass(proxyClass);
|
||||
}
|
||||
|
||||
private String generateClassName(Class<?> clazz) {
|
||||
return String.format(classNameTemplate, clazz.getSimpleName(), proxyClassCounter.incrementAndGet());
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.core.aop.proxy;
|
||||
|
||||
import fun.asgc.neutrino.core.base.GlobalConfig;
|
||||
import fun.asgc.neutrino.core.util.FileUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -47,8 +50,10 @@ public class ProxyClassLoader extends ClassLoader {
|
||||
}
|
||||
|
||||
public Class<?> loadProxyClass(ProxyClass proxyClass) {
|
||||
for (Map.Entry<String, byte[]> e : proxyClass.getByteCode().entrySet()) {
|
||||
byteCodeMap.putIfAbsent(e.getKey(), e.getValue());
|
||||
if (null != proxyClass.getByteCode()) {
|
||||
for (Map.Entry<String, byte[]> e : proxyClass.getByteCode().entrySet()) {
|
||||
byteCodeMap.putIfAbsent(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -61,6 +66,9 @@ public class ProxyClassLoader extends ClassLoader {
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
byte[] bytes = byteCodeMap.get(name);
|
||||
if (null == bytes) {
|
||||
bytes = FileUtil.readBytes( GlobalConfig.getGeneratorCodeSavePath() + name.replaceAll("\\.", "/") + ".class");
|
||||
}
|
||||
if (bytes != null) {
|
||||
Class<?> ret = defineClass(name, bytes, 0, bytes.length);
|
||||
byteCodeMap.remove(name);
|
||||
|
||||
@@ -21,25 +21,39 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.core.aop.proxy;
|
||||
|
||||
import fun.asgc.neutrino.core.base.GlobalConfig;
|
||||
import fun.asgc.neutrino.core.util.FileUtil;
|
||||
import fun.asgc.neutrino.core.util.SystemUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/24
|
||||
*/
|
||||
@Slf4j
|
||||
public class ProxyCompiler {
|
||||
/**
|
||||
* 收集编译过程信息
|
||||
*/
|
||||
private static DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
|
||||
|
||||
protected volatile List<String> options = null;
|
||||
protected volatile boolean isUnpack = false;
|
||||
|
||||
|
||||
protected List<String> getOptions() {
|
||||
|
||||
|
||||
if (options != null) {
|
||||
return options;
|
||||
}
|
||||
@@ -57,6 +71,8 @@ public class ProxyCompiler {
|
||||
if (cp != null && cp.trim().length() != 0) {
|
||||
ret.add("-classpath");
|
||||
ret.add(cp);
|
||||
|
||||
System.out.println("classpath:" + cp);
|
||||
}
|
||||
|
||||
options = ret;
|
||||
@@ -68,35 +84,46 @@ public class ProxyCompiler {
|
||||
* 兼容 tomcat 丢失 class path,否则无法编译
|
||||
*/
|
||||
protected String getClassPath() {
|
||||
URLClassLoader classLoader = getURLClassLoader();
|
||||
if (classLoader == null) {
|
||||
return null;
|
||||
if (!SystemUtil.isStartupFromJar()) {
|
||||
URLClassLoader classLoader = getURLClassLoader();
|
||||
if (classLoader == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
boolean isWindows = isWindows();
|
||||
StringBuilder ret = new StringBuilder();
|
||||
for (URL url : classLoader.getURLs()) {
|
||||
if (index++ > 0) {
|
||||
ret.append(File.pathSeparator);
|
||||
}
|
||||
|
||||
String path = url.getFile();
|
||||
|
||||
// 如果是 windows 系统,去除前缀字符 '/'
|
||||
if (isWindows && path.startsWith("/")) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
|
||||
// 去除后缀字符 '/'
|
||||
if (path.length() > 1 && (path.endsWith("/") || path.endsWith(File.separator))) {
|
||||
path = path.substring(0, path.length() - 1);
|
||||
}
|
||||
ret.append(path);
|
||||
}
|
||||
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
boolean isWindows = isWindows();
|
||||
StringBuilder ret = new StringBuilder();
|
||||
for (URL url : classLoader.getURLs()) {
|
||||
if (index++ > 0) {
|
||||
ret.append(File.pathSeparator);
|
||||
List<String> list = new ArrayList<>();
|
||||
File file = new File(GlobalConfig.getGeneratorCodeSavePath() + "BOOT-INF/lib/");
|
||||
if (file.exists()) {
|
||||
File[] files = file.listFiles();
|
||||
for (File f : files) {
|
||||
list.add(f.getAbsolutePath());
|
||||
}
|
||||
|
||||
String path = url.getFile();
|
||||
|
||||
// 如果是 windows 系统,去除前缀字符 '/'
|
||||
if (isWindows && path.startsWith("/")) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
|
||||
// 去除后缀字符 '/'
|
||||
if (path.length() > 1 && (path.endsWith("/") || path.endsWith(File.separator))) {
|
||||
path = path.substring(0, path.length() - 1);
|
||||
}
|
||||
|
||||
ret.append(path);
|
||||
}
|
||||
|
||||
return ret.toString();
|
||||
list.add(GlobalConfig.getGeneratorCodeSavePath() + "BOOT-INF/classes/");
|
||||
return list.stream().collect(Collectors.joining(File.pathSeparator));
|
||||
}
|
||||
|
||||
protected boolean isWindows() {
|
||||
@@ -137,6 +164,67 @@ public class ProxyCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
public void compileToFile(ProxyClass proxyClass) {
|
||||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
if (compiler == null) {
|
||||
throw new RuntimeException("Can not get javax.tools.JavaCompiler, check whether \"tools.jar\" is in the environment variable CLASSPATH \n" +
|
||||
"Visit https://jfinal.com/doc/4-8 for details \n");
|
||||
}
|
||||
unpack();
|
||||
|
||||
File file = FileUtil.save(GlobalConfig.getGeneratorCodeSavePath() + proxyClass.getPkg().replaceAll("\\.", "/"), proxyClass.getName() + ".java", proxyClass.getSourceCode());
|
||||
StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(diagnostics, null, null);
|
||||
|
||||
Iterable<? extends JavaFileObject> iterable = standardFileManager.getJavaFileObjects(file);
|
||||
// 创建一个编译任务
|
||||
JavaCompiler.CompilationTask task = compiler.getTask(null, standardFileManager, diagnostics, getOptions(), null, iterable);
|
||||
//JavaCompiler.CompilationTask 实现了 Callable 接口
|
||||
Boolean result = task.call();
|
||||
printLog(result, file);
|
||||
}
|
||||
|
||||
private synchronized void unpack() {
|
||||
if (!SystemUtil.isStartupFromJar()) {
|
||||
return;
|
||||
}
|
||||
if (isUnpack) {
|
||||
return;
|
||||
}
|
||||
isUnpack = true;
|
||||
try {
|
||||
File file1 = new File(GlobalConfig.getGeneratorCodeSavePath() + "BOOT-INF/lib/");
|
||||
File file2 = new File(GlobalConfig.getGeneratorCodeSavePath() + "BOOT-INF/classes/");
|
||||
if (file1.exists() && file2.exists()) {
|
||||
return;
|
||||
}
|
||||
log.info("解压jar:{} 到:{}", SystemUtil.getCurrentJarFilePath(), GlobalConfig.getGeneratorCodeSavePath());
|
||||
FileUtil.unzipJar(GlobalConfig.getGeneratorCodeSavePath(), SystemUtil.getCurrentJarFilePath());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void printLog(Boolean result, File ...files){
|
||||
if (!result) {
|
||||
StringJoiner rs = new StringJoiner(System.getProperty("line.separator"));
|
||||
for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
|
||||
rs.add(String.format("%s:%s[line %d column %d]-->%s%n", diagnostic.getKind(), diagnostic.getSource(), diagnostic.getLineNumber(),
|
||||
diagnostic.getColumnNumber(),
|
||||
diagnostic.getMessage(null)));
|
||||
}
|
||||
System.out.println("编译失败,原因:" + rs.toString());
|
||||
log.error("编译失败,原因:{}", rs.toString());
|
||||
} else {
|
||||
System.out.println("编译成功");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Arrays.stream(files).forEach(file -> {
|
||||
sb.append(file.getName());
|
||||
sb.append(";");
|
||||
});
|
||||
log.info("编译成功:{}", sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected void outputCompileError(Boolean result, DiagnosticCollector<JavaFileObject> collector) {
|
||||
if (! result) {
|
||||
// collector.getDiagnostics().forEach(item -> log.error(item.toString()));
|
||||
|
||||
@@ -35,8 +35,19 @@ public class GlobalConfig {
|
||||
* 是否是容器启动
|
||||
*/
|
||||
private static volatile boolean isContainerStartup = false;
|
||||
/**
|
||||
* 是否保存生成的代码
|
||||
* 只是一个建议。
|
||||
* 当程序是普通运行时,采纳建议。
|
||||
* 当程序是以jar方式运行时,强制保存生成的代码
|
||||
*/
|
||||
private static volatile boolean isSaveGeneratorCode = false;
|
||||
/**
|
||||
* 自动生成代码保存路径
|
||||
*/
|
||||
private static volatile String generatorCodeSavePath = "./lib/";
|
||||
|
||||
public static boolean isIsPrintGeneratorCode() {
|
||||
public static boolean isPrintGeneratorCode() {
|
||||
return isPrintGeneratorCode;
|
||||
}
|
||||
|
||||
@@ -44,11 +55,27 @@ public class GlobalConfig {
|
||||
GlobalConfig.isPrintGeneratorCode = isPrintGeneratorCode;
|
||||
}
|
||||
|
||||
public static boolean isIsContainerStartup() {
|
||||
public static boolean isContainerStartup() {
|
||||
return isContainerStartup;
|
||||
}
|
||||
|
||||
public static void setIsContainerStartup(boolean isContainerStartup) {
|
||||
GlobalConfig.isContainerStartup = isContainerStartup;
|
||||
}
|
||||
|
||||
public static boolean isSaveGeneratorCode() {
|
||||
return isSaveGeneratorCode;
|
||||
}
|
||||
|
||||
public static void setIsSaveGeneratorCode(boolean isSaveGeneratorCode) {
|
||||
GlobalConfig.isSaveGeneratorCode = isSaveGeneratorCode;
|
||||
}
|
||||
|
||||
public static String getGeneratorCodeSavePath() {
|
||||
return generatorCodeSavePath;
|
||||
}
|
||||
|
||||
public static void setGeneratorCodeSavePath(String generatorCodeSavePath) {
|
||||
GlobalConfig.generatorCodeSavePath = generatorCodeSavePath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,13 @@ import org.apache.commons.io.FileDeleteStrategy;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -50,7 +57,6 @@ public class FileUtil {
|
||||
String subPath = path.substring(MetaDataConstant.CLASSPATH_RESOURCE_IDENTIFIER.length());
|
||||
return FileUtil.class.getResourceAsStream(subPath);
|
||||
}
|
||||
|
||||
return new FileInputStream(path);
|
||||
}
|
||||
|
||||
@@ -103,6 +109,11 @@ public class FileUtil {
|
||||
}
|
||||
|
||||
public static void write(String path, String content) {
|
||||
// try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(path), StandardCharsets.UTF_8)){
|
||||
// writer.write(content);
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(getOutputStream(path)))){
|
||||
bw.write(content);
|
||||
} catch (IOException e) {
|
||||
@@ -147,4 +158,39 @@ public class FileUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static File save(String path, String fileName, String content) {
|
||||
if (!path.endsWith("/")) {
|
||||
path += "/";
|
||||
}
|
||||
makeDirs(path);
|
||||
write(path + fileName, content);
|
||||
return new File(path + "/" + fileName);
|
||||
}
|
||||
|
||||
public static void unzipJar(String destinationDir, String jarPath) throws IOException {
|
||||
File file = new File(jarPath);
|
||||
JarFile jar = new JarFile(file);
|
||||
for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements();) {
|
||||
JarEntry entry = (JarEntry) enums.nextElement();
|
||||
String fileName = destinationDir + File.separator + entry.getName();
|
||||
File f = new File(fileName);
|
||||
if (fileName.endsWith("/")) {
|
||||
f.mkdirs();
|
||||
}
|
||||
}
|
||||
for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements();) {
|
||||
JarEntry entry = (JarEntry) enums.nextElement();
|
||||
String fileName = destinationDir + File.separator + entry.getName();
|
||||
File f = new File(fileName);
|
||||
if (!fileName.endsWith("/")) {
|
||||
InputStream is = jar.getInputStream(entry);
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
while (is.available() > 0) {
|
||||
fos.write(is.read());
|
||||
}
|
||||
fos.close();
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ package fun.asgc.neutrino.core.util;
|
||||
|
||||
import fun.asgc.neutrino.core.base.CodeBlock;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
@@ -85,6 +87,24 @@ public class SystemUtil {
|
||||
private void stop() {
|
||||
this.running = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isStartupFromJar() {
|
||||
String protocol = SystemUtil.class.getResource("").getProtocol();
|
||||
return Objects.equals(protocol, "jar");
|
||||
}
|
||||
|
||||
public static String getCurrentJarFilePath() {
|
||||
if (!isStartupFromJar()) {
|
||||
return null;
|
||||
}
|
||||
String url = SystemUtil.class.getResource("").getPath();
|
||||
if (url.startsWith("file:")) {
|
||||
url = url.substring(5);
|
||||
}
|
||||
if (url.contains("!")) {
|
||||
url = url.substring(0, url.indexOf("!"));
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@
|
||||
package fun.asgc.neutrino.proxy.server;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.NeutrinoApplication;
|
||||
import fun.asgc.neutrino.core.base.GlobalConfig;
|
||||
import fun.asgc.neutrino.core.context.NeutrinoLauncher;
|
||||
import fun.asgc.neutrino.core.util.SystemUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -34,6 +36,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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user