Java通过ClassLoader加载指定的Jar包,并读取Jar包内类上的注解
说明
项目上有个需求,在系统启动时需要动态的加载Jar包,并且扫描jar包中类的注解。
实现
package org.yingqiang.system.annotation.scanner;
import java.io.*;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarInputStream;
import java.util.zip.ZipEntry;
/**
* 查找jar包下的类是否包含Annotation
*/
public final class JarAnnotationScanner {
private File jarFile;
public JarAnnotationScanner(File jarFile) {
this.jarFile = jarFile;
}
/**
* 扫描
*
* @param annotationClass
*/
public List<Class>> scan(Class extends annotation> annotationClass) {
List<Class>> classList = new ArrayList<>();
try (JarInputStream jarInputStream = new JarInputStream(new FileInputStream(jarFile))) {
ZipEntry zipEntry;
while ((zipEntry = jarInputStream.getNextEntry()) != null) {
String entryName = zipEntry.getName();
if (entryName.endsWith(".class")) {
String className = entryName.replace(".class", "").replaceAll("/", ".");
className = className.replaceAll("\\$", ".");
byte[] classData = loadClassData(jarInputStream);
JarClassLoader jarClassLoader = new JarClassLoader(classData);
try {
Class> clazz = jarClassLoader.findClass(className);
Annotation annotation = clazz.getAnnotation(annotationClass);
if (annotation != null) {
classList.add(clazz);
}
} catch (Exception e) {
// ignore
}
}
jarInputStream.closeEntry();
}
} catch (Exception | NoClassDefFoundError e) {
System.err.println(e.getMessage());
}
return classList;
}
/**
* @param inputStream
* @return
* @throws IOException
*/
private byte[] loadClassData(InputStream inputStream) throws IOException {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
return baos.toByteArray();
}
}
private class JarClassLoader extends ClassLoader {
private byte[] classData;
public JarClassLoader(byte[] classData) {
this.classData = classData;
}
@Override
protected Class> findClass(String name) throws ClassNotFoundException {
return defineClass(name, classData, 0, classData.length);
}
}
/**
* @param clazz
* @return
*/
public static String getPackageName(Class> clazz) {
if (clazz != null) {
return clazz.getName().substring(0, clazz.getName().lastIndexOf('.'));
}
return "";
}
}
测试
package org.yingqiang.system.annotation.scanner;
import java.io.File;
import java.lang.annotation.Annotation;
import java.util.List;
public class JarAnnotationScannerTest {
public static void main(String[] args) {
File jarFile = new File("D:\\Temp\\addon\\sms-email.jar");
JarAnnotationScanner jarAnnotationScanner = new JarAnnotationScanner(jarFile);
String annotationClassString = "org.springframework.boot.autoconfigure.SpringBootApplication";
Class> annotationClass = null;
try {
annotationClass = Class.forName(annotationClassString);
} catch (ClassNotFoundException e) {
// e.printStackTrace();
}
List<Class>> classList = jarAnnotationScanner.scan((Class extends annotation>) annotationClass);
for (Class> clazz : classList) {
System.out.println(clazz.getName());
System.out.println(JarAnnotationScanner.getPackageName(clazz));
}
}
}