获取到包含某注解的所有类

首先先要获取到applicationContext
只要类 implements ApplicationContextAware就会自动注入到类里的applicationContext
话不多说直接上代码

@Component
@Slf4j
public class test implements ApplicationContextAware {

	private static ApplicationContext applicationContext;
	
	public void test(Class<? extends Annotation> annotation){
		List<Class<?>> inClassList = new ArrayList<>();
		Map<Class<?>, Set<Method>> containsMap = new HashMap<>();
		//获取到所有包含@RestController 或者 @Controller的bean
		Map<String, Object> beanList = applicationContext.getBeansWithAnnotation(RestController.class);
		beanList.putAll(applicationContext.getBeansWithAnnotation(Controller.class));
		beanList.forEach((k, v) -> inClassList.add(applicationContext.getType(k)));
		getClassesWithAnnotationFromAllClasses(inClassList, annotation,  containsMap);
	}
}

inClassList里就可以获取到所有的包含@RestController 或者 @Controller 的bean了

获取类集合里所有包含自定义注解的方法名

/**
     * 获取类里所有包含annotation的方法名
     *
     * @param inClassList  需过滤其中方法的class集合
     * @param annotation   注解class
     * @param map          包含该annotation的map,key为controller类,集合中为方法
     */
    private void getMethodsWithAnnotationFromAllClasses(List<Class<?>> inClassList,
                                                        Class<? extends Annotation> annotation, Map<Class<?>, Set<Method>> map) {
        for (Class<?> myClasss : inClassList) {
            Method[] methods = myClasss.getMethods();
            Set<Method> methodList = new HashSet<>();
            for (Method method : methods) {
            //findAnnotation也可以拿到其父类是否包含该注解
                if (null != method && null != AnnotationUtils.findAnnotation(method, annotation)) {
                    try {
                        methodList.add(method);
                    }catch (Exception e){
                        log.error(e.toString());
                    }
                }
            }

            if (methodList.size() > 0) {
                map.put(myClasss, methodList);
            }

        }

获取所有包含某注解的方法及获取其URI

最后一步就是获取方法的URI了,直接把完整的代码贴出来

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;


@Component
@Slf4j
public class test implements ApplicationContextAware {

    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    private static ApplicationContext applicationContext;

    public Set<String[]> test(Class<? extends Annotation> annotation) {
        List<Class<?>> inClassList = new ArrayList<>();
        Map<Class<?>, Set<Method>> containsMap = new HashMap<>();
        //获取到所有包含@RestController 或者 @Controller的bean
        Map<String, Object> beanList = applicationContext.getBeansWithAnnotation(RestController.class);
        beanList.putAll(applicationContext.getBeansWithAnnotation(Controller.class));
        beanList.forEach((k, v) -> inClassList.add(applicationContext.getType(k)));
        getMethodsWithAnnotationFromAllClasses(inClassList, annotation, containsMap);
        Set<String[]> resultList = new HashSet<>();
        //获取所有uri的集合
        Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : map.entrySet()) {
            HandlerMethod method = entry.getValue();
            for (Map.Entry<Class<?>, Set<Method>> classEntry : containsMap.entrySet()) {
                Set<Method> str = classEntry.getValue();
                Set<String> methodNameSet = str.stream().map(Method::getName).collect(Collectors.toSet());
                //如果controller匹配到了containsMap的key且方法存在于containsMap的value里,将其uri加入resultList
                String controllerName = classEntry.getKey().getName();
                String methodName = method.getBeanType().getName();
                //controllerName拿到的是代理beanName,需要处理
                if (controllerName.contains("$$")) {
                    controllerName = controllerName.substring(0, controllerName.indexOf("$$"));
                }
                try {
                    if (controllerName.equals(methodName) && methodNameSet.contains(method.getMethod().getName())) {
                        //获取uri
                        for (RequestMethod m : entry.getKey().getMethodsCondition().getMethods()) {
                            for (String pattern : entry.getKey().getPatternsCondition().getPatterns()) {
                                String[] resultArr = new String[2];
                                resultArr[0] = m.name();
                                resultArr[1] = pattern;
                                resultList.add(resultArr);
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error(e.toString());
                }
            }
        }
        return resultList;
    }

    /**
     * 获取类里所有包含annotation的方法名
     *
     * @param inClassList 需过滤其中方法的class集合
     * @param annotation  注解class
     * @param map         包含该annotation的map,key为controller类,集合中为方法
     */
    private void getMethodsWithAnnotationFromAllClasses(List<Class<?>> inClassList,
                                                        Class<? extends Annotation> annotation, Map<Class<?>, Set<Method>> map) {
        for (Class<?> myClasss : inClassList) {
            Method[] methods = myClasss.getMethods();
            Set<Method> methodList = new HashSet<>();
            for (Method method : methods) {
                //findAnnotation也可以拿到其父类是否包含该注解
                if (null != method && null != AnnotationUtils.findAnnotation(method, annotation)) {
                    try {
                        methodList.add(method);
                    } catch (Exception e) {
                        log.error(e.toString());
                    }
                }
            }

            if (methodList.size() > 0) {
                map.put(myClasss, methodList);
            }

        }

    }
}

使用ApplicationRunner以在容器启动完成的时候获取列表

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class ServiceStarted implements ApplicationRunner {
    @Autowired
    Test test;
    @Override
    public void run(ApplicationArguments args){
        Set<String[]> sets = test.test(TestAnnotation.class);
        log.info("获取到列表{}",sets);
        //dosomething
    }
}

拿到列表后就可以dosomething了,保存到本地文件夹、保存至redis、或者也可以在这一步进行对类操作,都可以
set[0] 为method 即 POST GET DELETE
set [1] 为该方法的uri

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐