java获取包下所有的类

1.背景

给一个Java的包名,获取包名下的所有类..

根据类上的注解,可以展开很多统一操作的业务

2.直接看代码-spring环境下

package com.qxnw.digit.scm.common.config.mq.supplier;

import com.qxnw.digit.scm.common.config.mq.MqRegister;
import lombok.extern.slf4j.Slf4j;
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.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @Copyright (C) XXXXX技有限公司
 * @Author: ldp
 * @Date: 2023/4/19 10:41
 * @Description:
 */
@Slf4j
public class MqSupplierConstHelp {
    private final static String RESOURCE_PATTERN = "/**/*.class";

    /**
     * 获取当前包路径下的供应商队列
     *
     * @return
     * @throws Exception
     */
    public Set<String> getSupplierQueueList() throws Exception {
        String basePackageName = this.getClass().getPackage().getName();
        log.info("basePackageName=" + basePackageName);
        // 获取到class字节码集合
        List<Class<?>> classList = getClassList(basePackageName);
        // 获取到带有注解的字段值
        Set<String> fieldQueueNameList = getFieldQueueName(classList);
        return fieldQueueNameList;
    }

    /**
     * 通过包名获取项目包下所有类
     *
     * @param BASE_PACKAGE 包名
     * @return
     */
    public static List<Class<?>> getClassList(String BASE_PACKAGE) {
        List<Class<?>> classes = new ArrayList<>();
        //spring工具类,可以获取指定路径下的全部类
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        try {
            String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE) + RESOURCE_PATTERN;
            Resource[] resources = resourcePatternResolver.getResources(pattern);
            //MetadataReader 的工厂类
            MetadataReaderFactory readerfactory = new CachingMetadataReaderFactory(resourcePatternResolver);
            for (Resource resource : resources) {
                //用于读取类信息
                MetadataReader reader = readerfactory.getMetadataReader(resource);
                //扫描到的class
                String classname = reader.getClassMetadata().getClassName();
                log.info("classname={}", classname);
                Class<?> clazz = Class.forName(classname);
                classes.add(clazz);
            }
        } catch (Exception e) {
            log.error("获取class异常:", e);
        }
        return classes;
    }

    /**
     * 根据字节码,获取带有注解的常量对象的字段值
     *
     * @param classList
     * @return
     * @throws Exception
     */
    private Set<String> getFieldQueueName(List<Class<?>> classList) throws Exception {
        Set<String> set = new HashSet();
        for (Class<?> aClass : classList) {
            MqRegister mqRegister = aClass.getAnnotation(MqRegister.class);
            if (mqRegister == null) {
                continue;
            }
            log.info("可以注册的常量对象:{}", aClass.getName());
            Object mqConst = aClass.newInstance();
            // 可以注册
            Field[] fields = aClass.getFields();
            for (Field field : fields) {
                String fieldName = field.getName();
                String queueName = field.get(mqConst).toString();
                log.info("可以注册的字段名称:" + fieldName + ",字段值:" + queueName);
                set.add(queueName);
            }
        }
        return set;
    }
}

 

3.直接看代码-非sping环境

package com.common.config.mq.supplier;

import com.common.config.mq.MqRegister;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;

/**
 * @Copyright (C) XXXXX技有限公司
 * @Author: ldp
 * @Date: 2023/4/19 10:41
 * @Description:
 */
@Slf4j
public class MqSupplierConstHelp {

    /**
     * 获取当前包路径下的队列
     *
     * @return
     * @throws Exception
     */
    public Set<String> getSupplierQueueList() throws Exception {
        String basePackageName = this.getClass().getPackage().getName();
        log.info("basePackageName=" + basePackageName);
        // 获取包的磁盘路径
        String dirPath = getDirPath(basePackageName);
        // 获取磁盘路径下的Java对象
        List<String> classNameList = getClassNameList(dirPath);
        log.info("classNameList" + classNameList);
        // 获取到class字节码集合
        List<Class<?>> classList = getClassList(classNameList, basePackageName);
        // 获取到带有注解的字段值
        Set<String> fieldQueueNameList = getFieldQueueName(classList);
        return fieldQueueNameList;
    }

    /**
     * 根据包名获取磁盘路径
     *
     * @param basePackageName
     * @return
     * @throws Exception
     */
    private String getDirPath(String basePackageName) throws Exception {
        String path = basePackageName.replace(".", "\\");
        ClassLoader loader = ClassLoader.getSystemClassLoader();
        //获取编译后的class文件夹路径dirPath
        Enumeration<URL> enums = loader.getResources(path);
        String dirPath = "";
        while (enums.hasMoreElements()) {
            URL url = enums.nextElement();
            if (url != null) {
                String protool = url.getProtocol();
                if ("file".equals(protool)) {
                    dirPath = url.getPath();
                    dirPath = URLDecoder.decode(dirPath, "utf-8");
                    log.info("dirPath=" + dirPath);
                }
            }
        }
        return dirPath;
    }

    /**
     * 获取磁盘路径下的Java对象
     *
     * @param dirPath
     * @return
     */
    private List<String> getClassNameList(String dirPath) {
        List<String> classNameList = new ArrayList<>();
        //根据传入文件夹路径创建File对象
        File dir = new File(dirPath);
        //检查是否为文件夹
        if (dir.isDirectory()) {
            //遍历文件夹内的文件
            for (File f : dir.listFiles()) {
                //获取文件名,并删除后缀 xxx.class
                String fileName = f.getName();
                String[] split = fileName.split("\\.");
                if (split.length != 2) {
                    continue;
                }
                if (!split[1].equals("class")) {
                    continue;
                }
                fileName = fileName.substring(0, fileName.lastIndexOf("."));
                //添加到结果中
                classNameList.add(fileName);
            }
        }
        return classNameList;
    }

    /**
     * 拼接class全路径
     *
     * @param classNames
     * @param basePackageName
     * @return
     */
    private List<Class<?>> getClassList(List<String> classNames, String basePackageName) {
        //将获取到的包内文件名转换为反射对象
        List<Class<?>> classes = new ArrayList<>();
        for (String className : classNames) {
            try {
                classes.add(Class.forName(basePackageName + "." + className));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return classes;
    }

    /**
     * 根据字节码,获取带有注解的常量对象的字段值
     *
     * @param classList
     * @return
     * @throws Exception
     */
    private Set<String> getFieldQueueName(List<Class<?>> classList) throws Exception {
        Set<String> set = new HashSet();
        for (Class<?> aClass : classList) {
            MqRegister mqRegister = aClass.getAnnotation(MqRegister.class);
            if (mqRegister == null) {
                continue;
            }
            log.info("可以注册的常量对象:{}", aClass.getName());
            Object mqConst = aClass.newInstance();
            // 可以注册
            Field[] fields = aClass.getFields();
            for (Field field : fields) {
                String fieldName = field.getName();
                String queueName = field.get(mqConst).toString();
                log.info("可以注册的字段名称:" + fieldName + ",字段值:" + queueName);
                set.add(queueName);
            }
        }
        return set;
    }
}

 

完美!

posted @ 2023-04-19 11:32  李东平|一线码农  阅读(1345)  评论(0编辑  收藏  举报