diff --git a/pom.xml b/pom.xml
index da993b3..44ffd82 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
io.xjar
xjar
- v2.0.6
+ v2.0.7
xjar
@@ -40,6 +40,17 @@
2.0.1.RELEASE
provided
+
+ org.javassist
+ javassist
+ 3.23.2-GA
+
+
+ org.hibernate
+ hibernate-core
+ 5.4.3.Final
+ provided
+
diff --git a/src/main/java/io/xjar/XInjector.java b/src/main/java/io/xjar/XInjector.java
index f5eb6ef..9a98b75 100644
--- a/src/main/java/io/xjar/XInjector.java
+++ b/src/main/java/io/xjar/XInjector.java
@@ -4,7 +4,6 @@
import io.loadkit.Resource;
import org.apache.commons.compress.archivers.jar.JarArchiveEntry;
import org.apache.commons.compress.archivers.jar.JarArchiveOutputStream;
-
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
@@ -20,14 +19,23 @@
public class XInjector {
/**
- * 往JAR包中注入XJar框架的classes
- *
+ * 往JAR包中注入XJar框架、以及XJar依赖的classes
* @param zos jar包输出流
* @throws IOException I/O 异常
*/
public static void inject(JarArchiveOutputStream zos) throws IOException {
+ inject(Loaders.ant().load("io/xjar/**"), zos);
+ inject(Loaders.ant().load("javassist/**"), zos);
+ }
+
+ /**
+ * 往JAR包中注入Resource
+ * @param resources
+ * @param zos
+ * @throws IOException
+ */
+ private static void inject(Enumeration resources, JarArchiveOutputStream zos) throws IOException{
Set directories = new HashSet<>();
- Enumeration resources = Loaders.ant().load("io/xjar/**");
while (resources.hasMoreElements()) {
Resource resource = resources.nextElement();
String name = resource.getName();
@@ -47,5 +55,4 @@ public static void inject(JarArchiveOutputStream zos) throws IOException {
zos.closeArchiveEntry();
}
}
-
}
diff --git a/src/main/java/io/xjar/XJarFile.java b/src/main/java/io/xjar/XJarFile.java
new file mode 100644
index 0000000..44e7fb6
--- /dev/null
+++ b/src/main/java/io/xjar/XJarFile.java
@@ -0,0 +1,33 @@
+package io.xjar;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+/**
+ * XJar File
+ *
+ * @author Payne 646742615@qq.com
+ * 2019/1/25 14:54
+ */
+public class XJarFile extends JarFile {
+ private final ClassLoader classLoader;
+
+ public XJarFile(String name, ClassLoader classLoader) throws IOException {
+ super(name);
+ this.classLoader = classLoader;
+ }
+
+ @Override
+ public synchronized InputStream getInputStream(ZipEntry zipEntry) throws IOException {
+ final String BOOT_INF_CLASSES = "BOOT-INF/classes/";
+ String name = zipEntry.getName();
+ if (name.startsWith(BOOT_INF_CLASSES)) {
+ URL url = classLoader.getResource(name.substring(BOOT_INF_CLASSES.length()));
+ return url != null ? url.openStream() : super.getInputStream(zipEntry);
+ }
+ return super.getInputStream(zipEntry);
+ }
+}
diff --git a/src/main/java/io/xjar/boot/XBootClassLoader.java b/src/main/java/io/xjar/boot/XBootClassLoader.java
index aa2be80..427b7ff 100644
--- a/src/main/java/io/xjar/boot/XBootClassLoader.java
+++ b/src/main/java/io/xjar/boot/XBootClassLoader.java
@@ -4,8 +4,10 @@
import io.xjar.XEncryptor;
import io.xjar.XKit;
import io.xjar.key.XKey;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtMethod;
import org.springframework.boot.loader.LaunchedURLClassLoader;
-
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -55,6 +57,13 @@ public Enumeration findResources(String name) throws IOException {
@Override
protected Class> findClass(String name) throws ClassNotFoundException {
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ if ("org.hibernate.boot.archive.internal.JarFileBasedArchiveDescriptor".equals(name)){
+ return findJarFileBasedArchiveDescriptor(name);
+ }
+ if ("org.hibernate.boot.archive.spi.AbstractArchiveDescriptor".equals(name)){
+ return findAbstractArchiveDescriptor(name);
+ }
try {
return super.findClass(name);
} catch (ClassFormatError e) {
@@ -73,6 +82,73 @@ protected Class> findClass(String name) throws ClassNotFoundException {
}
}
+ /**
+ * 加载该类后将该类缓存到classPool,注入的源码要用
+ * @param name
+ * @return
+ * @throws ClassNotFoundException
+ */
+ private Class findAbstractArchiveDescriptor(String name) throws ClassNotFoundException{
+ URL resource = findResource(name.replace('.', '/') + ".class");
+ try {
+ InputStream in = resource.openStream();
+ ClassPool classPool = ClassPool.getDefault();
+ CtClass ctClass = classPool.makeClass(in);
+ return ctClass.toClass();
+ }catch (Exception e){
+ e.printStackTrace();
+ throw new ClassNotFoundException(name);
+ }
+ }
+
+ /**
+ * 加载hibernate的org.hibernate.boot.archive.internal.JarFileBasedArchiveDescriptor类
+ * 之后动态修改resolveJarFileReference实现兼容访问加密的xjar
+ * @param name
+ * @return
+ * @throws Exception
+ */
+ private Class findJarFileBasedArchiveDescriptor(String name) throws ClassNotFoundException{
+ String methodName = "resolveJarFileReference";
+// Thread.currentThread().setContextClassLoader(this.getParent());
+ try {
+ /**
+ * 这里的ClassPool类和动态注入源码中的class可能是不同的classloader加载,
+ * 导致classNotFound,所以在这手动使用本classLoader加载
+ */
+ loadClass("org.hibernate.boot.archive.spi.ArchiveDescriptor");
+ loadClass("org.hibernate.boot.archive.spi.AbstractArchiveDescriptor");
+ loadClass("java.util.jar.JarFile");
+ loadClass("io.xjar.XJarFile");
+ loadClass("java.lang.Exception");
+ URL resource = findResource(name.replace('.', '/') + ".class");
+ InputStream in = resource.openStream();
+ ClassPool classPool = ClassPool.getDefault();
+ CtClass ctClass = classPool.makeClass(in);
+ CtMethod resolveJarFileReferenceMethod = ctClass.getDeclaredMethod(methodName);
+ resolveJarFileReferenceMethod.setBody(""
+ + "{try {\n" +
+ "final String filePart = super.getArchiveUrl().getFile();\n" +
+ "if ( filePart != null && filePart.indexOf( ' ' ) != -1 ) {\n" +
+ "java.util.jar.JarFile jarFile = new java.util.jar.JarFile( super.getArchiveUrl().getFile() );" +
+ "return new io.xjar.XJarFile(jarFile.getName(), ((Object)this).getClass().getClassLoader());\n" +
+ "}\n" +
+ "else {\n" +
+ "java.util.jar.JarFile jarFile = new java.util.jar.JarFile( super.getArchiveUrl().toURI().getSchemeSpecificPart() );" +
+ "return new io.xjar.XJarFile(jarFile.getName(), ((Object)this).getClass().getClassLoader());\n" +
+ "}\n" +
+ "}\n" +
+ "catch (Exception e) {\n" +
+ "e.printStackTrace();\n" +
+ "}\n" +
+ "return null;}");
+ return ctClass.toClass();
+ }catch (Exception e){
+ e.printStackTrace();
+ throw new ClassNotFoundException(name);
+ }
+ }
+
private class XBootEnumeration implements Enumeration {
private final Enumeration enumeration;