
io.jboot.utils.ClassScanner Maven / Gradle / Ivy
/**
* Copyright (c) 2015-2017, Michael Yang 杨福海 ([email protected]).
*
* Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl-3.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jboot.utils;
import com.jfinal.kit.PathKit;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* 类扫描器
*/
public class ClassScanner {
private static final Set appClasses = new HashSet<>();
public static List> scanSubClass(Class pclazz) {
return scanSubClass(pclazz, false);
}
public static List> scanSubClass(Class pclazz, boolean mustCanNewInstance) {
if (pclazz == null) {
throw new RuntimeException("pclazz cannot be null");
}
if (appClasses.isEmpty()) {
initAppClasses();
}
List> classes = new ArrayList<>();
findClassesByParent(classes, pclazz, mustCanNewInstance);
return classes;
}
public static List scanClass() {
return scanClass(false);
}
public static List scanClass(boolean mustCanNewInstance) {
if (appClasses.isEmpty()) {
initAppClasses();
}
List list = new ArrayList<>();
if (mustCanNewInstance) {
for (Class clazz : appClasses) {
if (clazz.isInterface()
|| Modifier.isAbstract(clazz.getModifiers())) {
continue;
}
list.add(clazz);
}
} else {
list.addAll(appClasses);
}
return list;
}
public static List scanClassByAnnotation(Class annotationClass, boolean mustCanNewInstance) {
if (appClasses.isEmpty()) {
initAppClasses();
}
List list = new ArrayList<>();
for (Class clazz : appClasses) {
Annotation annotation = clazz.getAnnotation(annotationClass);
if (annotation == null) {
continue;
}
if (mustCanNewInstance) {
if (clazz.isInterface()
|| Modifier.isAbstract(clazz.getModifiers())) {
continue;
}
}
list.add(clazz);
}
return list;
}
/**
* 开发环境下,用于热加载后重新清空所有的类
*/
static void clearAppClasses() {
appClasses.clear();
}
private static void findClassesByParent(List> classes, Class pclazz, boolean mustCanNewInstance) {
for (Class clazz : appClasses) {
tryToaddClass(classes, pclazz, mustCanNewInstance, clazz);
}
}
private static void initAppClasses() {
initByFilePath(PathKit.getRootClassPath());
Set jars = new HashSet<>();
findJars(jars, ClassScanner.class.getClassLoader());
for (String path : jars) {
JarFile jarFile = null;
try {
jarFile = new JarFile(path);
Enumeration entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
String entryName = jarEntry.getName();
if (!jarEntry.isDirectory() && entryName.endsWith(".class")) {
String className = entryName.replace("/", ".").substring(0, entryName.length() - 6);
initAppClasses(classForName(className));
}
}
} catch (IOException e1) {
} finally {
if (jarFile != null)
try {
jarFile.close();
} catch (IOException e) {
}
}
}
}
private static void initByFilePath(String filePath) {
List classFileList = new ArrayList<>();
scanClassFile(classFileList, filePath);
for (File file : classFileList) {
int start = filePath.length();
int end = file.toString().length() - ".class".length();
String classFile = file.toString().substring(start + 1, end);
initAppClasses(classForName(classFile.replace(File.separator, ".")));
}
}
private static void initAppClasses(Class clazz) {
if (clazz != null)
appClasses.add(clazz);
}
private static void findJars(Set set, ClassLoader classLoader) {
try {
if (classLoader instanceof URLClassLoader) {
URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
URL[] urLs = urlClassLoader.getURLs();
String JAVA_HOME = new File(System.getProperty("java.home"), "..").getCanonicalPath();
for (URL url : urLs) {
String path = url.getPath();
// path : /d:/xxx
if (path.startsWith("/") && path.indexOf(":") == 2) {
path = path.substring(1);
}
if (!path.toLowerCase().endsWith(".jar")) {
initByFilePath(new File(path).getCanonicalPath());
}
if (!path.startsWith(JAVA_HOME)) {
set.add(url.getPath());
}
}
}
ClassLoader parent = classLoader.getParent();
if (parent != null) {
findJars(set, parent);
}
} catch (Throwable ex) {
ex.printStackTrace();
}
}
private static void tryToaddClass(List> classes, Class pclazz, boolean mustCanNewInstance, Class clazz) {
if (classes == null
|| pclazz == null
|| clazz == null
|| !pclazz.isAssignableFrom(clazz)) {
return;
}
if (!mustCanNewInstance) {
classes.add(clazz);
return;
}
if (clazz.isInterface()
|| Modifier.isAbstract(clazz.getModifiers())) {
return;
}
classes.add(clazz);
}
@SuppressWarnings("unchecked")
private static Class classForName(String className) {
try {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return Class.forName(className, false, cl);
} catch (Throwable ex) {
//ignore
}
return null;
}
private static void scanClassFile(List fileList, String path) {
File files[] = new File(path).listFiles();
if (null == files || files.length == 0)
return;
for (File file : files) {
if (file.isDirectory()) {
scanClassFile(fileList, file.getAbsolutePath());
} else if (file.getName().endsWith(".class")) {
fileList.add(file);
}
}
}
}