获取指定父类的所有子类及方法列表

前言

由于公司项目架构升级,所以要梳理项目中所有dao层的mapper及对应的方法,便于升级后的风险把控。

但由于我们这个项目模块较多,且老代码位置不统一,这几百个mapper连在哪个包下都不确定,所以人肉查找是不可行的。于是思考能否用代码直接输出一个方法列表。

思路

在思考的过程中,发现这个项目中所有的mapper接口都是统一用工具生成的,并且都继承了一个父mapper接口,所以就想到了能否用代码查找这个父mapper对应的子mapper,并且输出对应的方法。

下面这个方法是spring提供的,可以获取指定所有指定类型对应的bean,也就是说参数传个父类,会把容器中所有该类及子类对应的bean返回。

org.springframework.beans.factory.ListableBeanFactory#getBeansOfType(java.lang.Class<T>)

<T> Map<String, T> getBeansOfType(@Nullable Class<T> var1) throws BeansException;

实现

项目是springboot的,所以直接写个工具类封装上面的方法,再写个专门输出用的controller,项目启动后一调用就可以了,代码如下

SpringUtils 工具类

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringUtils implements ApplicationContextAware, BeanFactoryPostProcessor {

    private static ApplicationContext applicationContext;

    private static ConfigurableListableBeanFactory beanFactory;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringUtils.applicationContext == null) {
            SpringUtils.applicationContext = applicationContext;
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        if (SpringUtils.beanFactory == null) {
            SpringUtils.beanFactory = beanFactory;
        }
    }

    /**
     * 获取applicationContext
     *
     * @return
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public static ConfigurableListableBeanFactory getBeanFactory() {
        return beanFactory;
    }

    /**
     * 通过name获取 Bean.
     *
     * @param name
     * @return
     */
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    /**
     * 通过class获取Bean
     *
     * @param clazz
     * @param 
     * @return
     */
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    /**
     * 通过name,以及Clazz返回指定的Bean
     *
     * @param name
     * @param clazz
     * @param 
     * @return
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }

}

Controller

import com.xxxx.OpenApiBaseMapper;
import com.xxxx.SpringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author ctl
 * @date 2021/9/9
 */
@RestController
public class Controller {

    /**
     * 获取OpenApiBaseMapper所有子接口的方法列表
     *
     * @return
     * @throws ClassNotFoundException
     */
    @GetMapping("/getMapperMethod")
    public Object test1() throws ClassNotFoundException {
        /*
         * getBeansOfType是获取spring容器中指定父类型的所有子类对应的bean
         *
         * 注意:本例子中所有mapper都是接口,子类也是接口,实现类是mybatis生成的代理对象
         *      map的key是子接口的类名,value是子接口对应的代理对象
         *      如果子类不是接口,value就是子类对应的bean,下面也无需再获取接口的名字了
         */
        Map<String, OpenApiBaseMapper> beansOfType = SpringUtils.getBeanFactory().getBeansOfType(OpenApiBaseMapper.class);
        List<String> list = new ArrayList<>();
        for (OpenApiBaseMapper value : beansOfType.values()) {
            // 获取代理对象的方法列表
            Method[] methods = value.getClass().getMethods();
            // 获取代理对象的接口,也就是OpenApiBaseMapper的子接口,
            // 如果子类不是接口,这步就没必要了 直接遍历methods 输出并返回 value.getClass().getName()+ "." + method.getName()即可
            Class<?>[] interfaces = value.getClass().getInterfaces();
            // 生成的代理对象只有一个实现接口 所以interfaces的size是1 写的时候懒得判断了 直接遍历了
            for (Class<?> anInterface : interfaces) {
                for (Method method : methods) {
                    // anInterface.getName()获取到的是子接口的全路径类名
                    // 用接口名拼方法名 输出并返回
                    System.out.println(anInterface.getName() + "." + method.getName());
                    list.add(anInterface.getName() + "." + method.getName());
                }
            }
        }
        System.out.println(list.size());
        return list;
    }
}

注:这个例子比标题说的“获取指定父类的所有子类及方法列表”要复杂一些,因为父类是个interface,子类也都是interface,SpringUtils返回的都是mybatis生成的代理对象。如果父类子类都是普通的class,不涉及代理对象,要更简单一些,上面方法中的注释已经写明。例子中返回的是所有的方法列表,如果想区分开子类列表和方法列表,稍作调整即可。

你可能感兴趣的:(Java基础,spring,java,spring,boot)