Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>io.xjar</groupId>
<artifactId>xjar</artifactId>
<version>v2.0.6</version>
<version>v2.0.7</version>

<name>xjar</name>

Expand Down Expand Up @@ -40,6 +40,17 @@
<version>2.0.1.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.23.2-GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.3.Final</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
Expand Down
17 changes: 12 additions & 5 deletions src/main/java/io/xjar/XInjector.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<Resource> resources, JarArchiveOutputStream zos) throws IOException{
Set<String> directories = new HashSet<>();
Enumeration<Resource> resources = Loaders.ant().load("io/xjar/**");
while (resources.hasMoreElements()) {
Resource resource = resources.nextElement();
String name = resource.getName();
Expand All @@ -47,5 +55,4 @@ public static void inject(JarArchiveOutputStream zos) throws IOException {
zos.closeArchiveEntry();
}
}

}
33 changes: 33 additions & 0 deletions src/main/java/io/xjar/XJarFile.java
Original file line number Diff line number Diff line change
@@ -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 [email protected]
* 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);
}
}
78 changes: 77 additions & 1 deletion src/main/java/io/xjar/boot/XBootClassLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -55,6 +57,13 @@ public Enumeration<URL> 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) {
Expand All @@ -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<URL> {
private final Enumeration<URL> enumeration;

Expand Down