前言
由于公司项目架构升级,所以要梳理项目中所有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 <T>
* @return
*/
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
/**
* 通过name,以及Clazz返回指定的Bean
*
* @param name
* @param clazz
* @param <T>
* @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,不涉及代理对象,要更简单一些,上面方法中的注释已经写明。例子中返回的是所有的方法列表,如果想区分开子类列表和方法列表,稍作调整即可。