从Spring源码中抽离的一个类扫描工具,可以获取项目中感兴趣的任何class

参考Spring的@CompomentScan注解扫描机制写的一个工具类。可以收集项目中的非SpringBean的class对象。比如收藏所有带MyBatisPlus注解@TableName的实体类。收藏某一个非bean接口的实现。收藏某一类泛型的所有实例等。后续文章介绍下其具体用途。

@Component
public class InterestedClassProcessor implements BeanPostProcessor, InitializingBean, EnvironmentAware, ResourceLoaderAware, EasyApplicationRunner {

    private Environment environment;

    static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";

    private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

    private MetadataReaderFactory metadataReaderFactory;

    private List<AnnotationMetadata> annotationMetadataContainer = new ArrayList<>();

    private ClassLoader classLoader;

    @AutowiredFalse
    private List<InterestedPackageRegister> registers;


    @SneakyThrows
    @Override
    public Object postProcessAfterInitialization(@NotNull Object bean, String beanName) throws BeansException {
    	// 模拟Aware机制,将感兴趣的class收集到具体对象中。
        if (bean instanceof InterestedClassAware) {
            InterestedClassAware interestedClassAware = (InterestedClassAware) bean;
            Set<Class<?>> classes = new HashSet<>();
            for (AnnotationMetadata annotationMetadata : annotationMetadataContainer) {
                if (interestedClassAware.match(annotationMetadata)) {
                    String className = annotationMetadata.getClassName();
                    Class<?> aClass = ClassUtils.forName(className, classLoader);
                    classes.add(aClass);
                }
            }
            interestedClassAware.setClasses(classes);
        }
        return bean;
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        Resource[] resources = findResources();
        for (Resource resource : resources) {
            if (!resource.isReadable()) {
                continue;
            }
            MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
            AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
            // 只取本公司的所有类
            if (need2Cache(annotationMetadata)) {
                annotationMetadataContainer.add(annotationMetadata);
            }
        }
    }

    @Override
    public void setEnvironment(@NotNull Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setResourceLoader(@NotNull ResourceLoader resourceLoader) {
        this.classLoader = resourceLoader.getClassLoader();
        this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
    }


    @Override
    public void doBusiness() {
        // 清掉,不让占着内存不释放,由不同的Aware接口的成员变量存储
        annotationMetadataContainer = null;
    }

    protected String resolveBasePackage(String basePackage) {
        return ClassUtils.convertClassNameToResourcePath(this.environment.resolveRequiredPlaceholders(basePackage));
    }

    private Resource[] findResources() throws IOException {
        String basePackage = "com.xxx.xxx";
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                resolveBasePackage(basePackage) + '/' + DEFAULT_RESOURCE_PATTERN;
        Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
        List<Resource> container = ZYListUtils.array2list(resources);

        // 子包注册
        if (ZYListUtils.isNotEmptyList(registers)) {
            for (InterestedPackageRegister register : registers) {
                String subPackage = register.getBasePackage();
                String subPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                        resolveBasePackage(subPackage) + '/' + DEFAULT_RESOURCE_PATTERN;
                Resource[] subResources = resourcePatternResolver.getResources(subPath);
                List<Resource> subContainer = ZYListUtils.array2list(subResources);
                container.addAll(subContainer);
            }
        }

        Resource[] result = new Resource[container.size()];
        for (int i = 0; i < result.length; i++) {
            result[i] = container.get(i);
        }
        return result;

    }

    // 简单的过滤掉一些没用的类
    private boolean need2Cache(AnnotationMetadata annotationMetadata) {
        String className = annotationMetadata.getClassName();
        return className.contains("xxxxCompany");
    }

}
public interface InterestedClassAware extends Aware {


    boolean match(AnnotationMetadata annotationMetadata);

    void setClasses(Set<Class<?>> classes);
}

你可能感兴趣的:(spring,java)