import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; import org.springframework.util.ClassUtils; import org.springframework.util.SystemPropertyUtils; import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; public class ScanUtils { private static final ResourcePatternResolver RESOLVER = new PathMatchingResourcePatternResolver(); private static final MetadataReaderFactory METADATA_READER_FACTORY = new SimpleMetadataReaderFactory(); /** * 掃描指定路徑下的所有類 * * @param scanPath 掃描路徑 * @param mustConcrete 掃描的類是否是具體的類,即非接口、非抽象類 * @return 掃描到的類 */ public static Set<Class<?>> scanClass(String scanPath, boolean mustConcrete) { String path = ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(scanPath)); String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + path + "/**/*.class"; Set<Class<?>> classes = new HashSet<>(); try { Resource[] resources = RESOLVER.getResources(packageSearchPath); for (Resource resource : resources) { if (resource.isReadable()) { MetadataReader metadataReader = METADATA_READER_FACTORY.getMetadataReader(resource); ClassMetadata classMetadata = metadataReader.getClassMetadata(); if (!mustConcrete || classMetadata.isConcrete()) { classes.add(Class.forName(classMetadata.getClassName())); } } } } catch (Exception e) { e.printStackTrace(); } return classes; } /** * 掃描指定路徑下指定超類的所有子類 * * @param scanPath 掃描路徑 * @param superclass 掃描的類的父類 * @param mustConcrete 掃描的類是否是具體的類,即非接口、非抽象類 * @return 掃描到的類 */ public static Set<Class<?>> scanSubclass(String scanPath, Class<?> superclass, boolean mustConcrete) { Set<Class<?>> scanClass = scanClass(scanPath, mustConcrete); return scanClass.stream().filter(superclass::isAssignableFrom).collect(Collectors.toSet()); } }