Two ways how SpringBoot obtains all Controller interfaces of the current project

Think about the business scenario, and only share the technical implementation. The following demo is written directly in the company project for convenience, so I want to comment on some sensitive information proper nouns, hope you understand.

First of all, we all know that Spring's IOC mechanism, all interfaces and services have a map container, which can be obtained through BeanFactory and ApplicationContext. Then we can operate from this.

Option One

(1) Think about any method or interface that can get the ApplicationContext. The answer is of course yes, the Aware interface. If you find an ApplicationContextAware, you can theoretically get the ApplicationContext container itself.

A detailed description of the Aware interface : Aware interface in SpringBoot
Insert picture description here
Insert picture description here

(2) The ApplicationContext is obtained, and the rest is actually to get the interface from it. Here, for convenience, I directly rewrite the run method after startup.

CommandLineRunner: By implementing this interface and overriding the run method, you can perform what you want to do after the startup class is completed. If multiple methods inherit the CommandLineRunner interface, multiple run methods must be executed, and there must be a sequence, plus @ Order(value =) can be assigned weight.

@Component
@Order(value = 2)
public class A implements CommandLineRunner{
    
    
@Override
public void run(String... strings) throws Exception {
    
    
   
    }
}

@Component
@Order(value = 1)
public class B implements CommandLineRunner {
    
    
@Override
public void run(String... strings) throws Exception {
    
    
   
    }
}

In this way, B must be executed before A after successful startup.
Going far, and speaking of it, just write for convenience:
Insert picture description here

@Override
    public void run(String... args) throws Exception {
    
    
        //获取使用RestController注解标注的的所有controller类
        Map<String, Object> controllers = applicationContext.getBeansWithAnnotation(RestController.class);
        //遍历每个controller层
        for (Map.Entry<String, Object> entry : controllers.entrySet()) {
    
    
            Object value = entry.getValue();
            System.out.println("拿到controller:"+entry.getKey()+",拿到value:"+value);
            Class<?> aClass = AopUtils.getTargetClass(value);
            System.out.println("拿到Class:"+aClass);
            }
            }
Start, look at the output directly:

Insert picture description here
You can see that GoodController and AnalysisController were found, but I did not find a Good2Controller that I specifically gave an example
Insert picture description here

The reason is that in Good2 I did not use the RestController annotation, but instead used @Controller + @ResponseBody. This is a small pit. Don't think that @Controller included in the RestController composite annotation will be found out of course. The result is not. Because this is based on the interface type, it doesn't care what is in your interface, as long as it is not RestController.class, it will not be found uniformly.

Insert picture description here
Insert picture description here

(3) We have successfully obtained all the controllers, but we all know that the interface refers to the public methods under the controller, so we continue to look down. Continue to add this line in the above code.

Insert picture description here
Running result:
Insert picture description here
successfully printed out~

(4) If we do not want to discover all the methods, but selectively discover methods such as Get, Post, Put, it is also very simple
    // 首先拿到所有的方法
	List<Method> declaredMethods = Arrays.asList(aClass.getDeclaredMethods());
            for (int i = 0; i < declaredMethods.size() ; i++) {
    
    
                // 下面开始根据注解类型进行输出统计
                GetMapping getMapping = declaredMethods.get(i).getAnnotation(GetMapping.class);
                PostMapping postMapping = declaredMethods.get(i).getDeclaredAnnotation(PostMapping.class);
                System.out.println("Get相关的:"+JSON.toJSONString(getMapping));
                System.out.println("Post相关的:"+JSON.toJSONString(postMapping));
            }
Success~!

Insert picture description here

(5) Provide the overall code. If you want to do statistics or some other interface, use Map and SET to implement it yourself:
public class EarlyWarningApplication implements ApplicationContextAware ,CommandLineRunner {
    
    

    // 定义一个私有的方便本class中调用
    private ApplicationContext applicationContext;

    // 通过重写ApplicationContextAware感知接口,将ApplicationContext赋值给当前的私有context容器
    @Override
    public void setApplicationContext(ApplicationContext arg0) {
    
    
        this.applicationContext = arg0;
    }

    public static void main(String[] args) {
    
    
        SpringApplication application = new SpringApplication(EarlyWarningApplication.class);
        application.run(args);
    }


    @Override
    public void run(String... args) throws Exception {
    
    
        
        Map<String, Object> controllers = applicationContext.getBeansWithAnnotation(RestController.class);
       
        for (Map.Entry<String, Object> entry : controllers.entrySet()) {
    
    
            Object value = entry.getValue();
            System.out.println("拿到controller:"+entry.getKey()+",拿到value:"+value);
            Class<?> aClass = AopUtils.getTargetClass(value);
            System.out.println("拿到Class:"+aClass);
            RequestMapping annotation = aClass.getAnnotation(RequestMapping.class);
            RequestMapping declaredAnnotation = aClass.getDeclaredAnnotation(RequestMapping.class);
           
            List<Method> methods = Arrays.asList(aClass.getMethods());
            System.out.println("Public Methods:" + methods);
            List<Method> declaredMethods = Arrays.asList(aClass.getDeclaredMethods());
            for (int i = 0; i < declaredMethods.size() ; i++) {
    
    
                GetMapping getMapping = declaredMethods.get(i).getAnnotation(GetMapping.class);
                PostMapping postMapping = declaredMethods.get(i).getDeclaredAnnotation(PostMapping.class);
                System.out.println("Get相关的:"+JSON.toJSONString(getMapping));
                System.out.println("Post相关的:"+JSON.toJSONString(postMapping));
            }
        }
    }
}

Option II

(1) A grand introduction to the WebApplicationContext global interface, which belongs to the son of ApplicationContext. It has many functions, but today! it's here! It is only used to get all public interfaces in each Controller~

Insert picture description here

(2) Write the code directly, write it directly in a Service or Controller, or write it anywhere:
 @Autowired
    WebApplicationContext applicationContext;

    @GetMapping("/getParam")
    public String getParam(){
    
    

        RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
        // 拿到Handler适配器中的全部方法
        Map<RequestMappingInfo, HandlerMethod> methodMap = mapping.getHandlerMethods();
        List<String> urlList = new ArrayList<>();
        for (RequestMappingInfo info : methodMap.keySet()){
    
    
           
            Set<String> urlSet = info.getPatternsCondition().getPatterns();
            // 获取全部请求方式
            Set<RequestMethod> Methods = info.getMethodsCondition().getMethods();
            System.out.println(Methods.toString());
            for (String url : urlSet){
    
    
                // 加上自己的域名和端口号,就可以直接调用
                urlList.add("http://localhost:XXXX"+url);
            }
        }
        return urlList.toString();
    }
Look at the results:

Insert picture description here

Insert picture description here

Success~

Guess you like

Origin blog.csdn.net/whiteBearClimb/article/details/109311769