一文详解SpringBoot中控制器的动态注册与卸载

2025-07-06 18:50

本文主要是介绍一文详解SpringBoot中控制器的动态注册与卸载,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《一文详解SpringBoot中控制器的动态注册与卸载》在项目开发中,通过动态注册和卸载控制器功能,可以根据业务场景和项目需要实现功能的动态增加、删除,提高系统的灵活性和可扩展性,下面我们就来看看Sp...

在项目开发中,通过动态注册和卸载控制器功能,可以根据业务场景和项目需要实现功能的动态增加、删除,提高系统的灵活性和可扩展性。

本文将介绍如何在 SpringBoot 中实现控制器的动态注册和卸载。

项目结构

src
└── main
    ├── Java
    │   └── com
    │       └── example
    │           ├── DynamicControllerApplication.java
    │           ├── controller
    │           │   ├── DemoController.java
    │           │   └── DynamicControllerRegistry.java
    │           │   └── DynamicController.java
    │           │   └── ControllerManagement.java
    │           └── config
    │               └── WebConfig.java
    └── resources
        └── application.properties

1. 创建 Spring Boot 启动类

首先,创建一个启动类 DynamicControllerApplication.java

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DynamicControllerApplication {
    public static void main(String[] args) {
        SpringApplication.run(DynamicControllerApplication.class, args);
    }
}

2. 创建一个测试控制器

接下来,我们创建一个控制器 DemoController.java,该控制器将返回简单的字符串响应。

// 动态控制器注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DynamicController {

    // 启动时注册
    boolean startupRegister() default true;

}

// 测试控制器
package com.example.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annoChina编程tation.RestController;

@RestController
@RequestMapping("/demo")
@DynamicController(startupRegister = false)
public class DemoController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello from Dynamic Controller!";
    }

}

3. 创建动态控制器注册类

然后,我们创建一个 DynamicControllerRegistry.java 类,用于动态注册和卸载控制器。

package com.example.controller;

import cn.hutool.core.util.ReflectUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@Component
@Slf4j
public class DynamicControllerRegistry {

    @Autowired
  php  private ApplicationContext applicationContext;

    @Autowired
    private RequestMappingHandlerMapping reChina编程questMappingHandlerMapping;

    private final Map<String, String> registeredControllers = new HashMap<>();

    public String registerController(Object controller,String methodName) {
        Class<?> controllerClass = controller.getClass();
        String key = key(controllerClass,methodName);
        String url = "";
        if (!registeredControllers.containsKey(key)) {
            Method m编程China编程ethod = ReflectUtil.getMethod(controllerClass,methodName);
            RequestMapping methodMapping = AnnotatedElementUtilswww.chinasem.cn.findMergedAnnotation(method, RequestMapping.class);
            RequestMapping requestMapping = controllerClass.getAnnotation(RequestMapping.class);

            url = getMethodUrl(requestMapping,methodMapping);
            // 注册控制器
            requestMappingHandlerMapping.registerMapping(
                    RequestMappingInfo.paths(url).methods(methodMapping.method()).build(),
                    controller,method
            );
            registeredControllers.put(key,url);
        }else{
            url = registeredControllers.get(key);
            log.warn("controller already registered:{}",url);
        }
        return url;
    }

    public String unregisterController(Class<?> controllerClass,Method method) {
        RequestMapping methodMapping = AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class);
        RequestMapping requestMapping = controllerClass.getAnnotation(RequestMapping.class);
        String url = getMethodUrl(requestMapping,methodMapping);
        RequestMappingInfo mappingInfo = RequestMappingInfo.paths(url).methods(methodMapping.method()).build();
        requestMappingHandlerMapping.unregisterMapping(mappingInfo);
        registeredControllers.remove(key(controllerClass,method.getName()));
        log.info("unregister controller:{}", url);
        return url;
    }

    public String unregisterController(Class<?> controllerClass,String methodName) {
        Method method = ReflectUtil.getMethod(controllerClass,methodName);
        return unregisterController(controllerClass,method);
    }

    private String key(Class<?> controllerClass, String method){
        return controllerClass.getName() + "." + method;
    }

    private String getMethodUrl(RequestMapping requestMapping,RequestMapping methodMapping){
        String baseUrl = "";
        String url = "";
        if(requestMapping != null){
            baseUrl = requestMapping.value()[0];
        }
        if(methodMapping != null) {
            String[] values = methodMapping.value();
            if (values.length > 0) {
                url = baseUrl + values[0];
            }
        }
        return url;
    }

}

4. 创建 Web 配置类

创建配置类 WebConfig.java ,实现项目启动时将不需要注册的控制器进行卸载。

package com.example.config;

import cn.hutool.core.util.ClassUtil;
import com.example.controller.DynamicController;
import com.example.controller.DynamicControllerRegistry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.RequestMapping;

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

@Configuration
@Slf4j
public class WebConfig {

    @Autowired
    private DynamicControllerRegistry dynamicControllerRegistry;

    @Bean
    public Void unregisterDynamicController() {
        Set<Class<?>> classes = ClassUtil.scanPackageByAnnotation("com.example", DynamicController.class);
        for(Class<?> clazz : classes) {
            DynamicController dynamicController = clazz.getAnnotation(DynamicController.class);
            boolean needRegister = dynamicController.startupRegister();
            if(needRegister) {
                continue;
            }

            // 默认不需要注册的controller,需要在启动时注销掉
            RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
            Method[] methods = clazz.getDeclaredMethods();
            for(Method method : methods) {
                dynamicControllerRegistry.unregisterController(clazz,method);
            }
        }

        return null;
    }
}

5. 创建动态控制器注册和卸载控制器

创建一个新的控制器 ControllerManagement.java,用于处理控制器的注册和卸载请求。

package com.example.controller;

import cn.hutool.extra.spring.SpringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/controller")
public class ControllerManagement {

    @Autowired
    private DynamicControllerRegistry dynamicControllerRegistry;

    @PostMapping("/register")
    public String registerController(@RequestParam String controllerBeanName, @RequestParam String methodName) {
        Object controller = SpringUtil.getBean(controllerBeanName);
        String url = dynamicControllerRegistry.registerController(controller, methodName);
        return "Controller registered at: " + url;
    }

    @DeleteMapping("/unregister")
    public String unregisterController(@RequestParam String controllerBeanName, @RequestParam String methodName) {
        Object controller = SpringUtil.getBean(controllerBeanName);
        String url = dynamicControllerRegistry.unregisterController(controller.getClass(),methodName);
        return "Controller unregistered from: " + url;
    }
}

6. 测试注册控制器

1. 启动服务

2. 访问 http://localhost:8080/demo/hello ,此时应该是404,因为没有注册控制器

3. POST http://localhost:8080/controller/register?methodName=hello&controllerBeanName=demoController 注册控制器

4. 再次访问 http://localhost:8080/demo/hello

7. 卸载控制器

1. POST http://localhost:8080/controller/unregister?methodName=hello&controllerBeanName=demoController 卸载控制器

2. 再次访问 <http://localhost:8080/demo/hello>,此时应该是404,因为控制器已被卸载

结论

通过以上步骤,我们实现了在 Spring Boot 中动态注册和卸载控制器的功能。

这样的实现能够根据实际需求动态增减功能。

到此这篇关于一文详解SpringBoot中控制器的动态注册与卸载的文章就介绍到这了,更多相关SpringBoot控制器注册与卸载内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!

这篇关于一文详解SpringBoot中控制器的动态注册与卸载的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1155314

相关文章

SpringBoot集成XXL-JOB实现任务管理全流程

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl... 目录一、前言二、项目结构简述三、Maven 依赖四、Controller 代码详解五、Service

Java中HashMap的用法详细介绍

《Java中HashMap的用法详细介绍》JavaHashMap是一种高效的数据结构,用于存储键值对,它是基于哈希表实现的,提供快速的插入、删除和查找操作,:本文主要介绍Java中HashMap... 目录一.HashMap1.基本概念2.底层数据结构:3.HashCode和equals方法为什么重写Has

Java 正则表达式的使用实战案例

《Java正则表达式的使用实战案例》本文详细介绍了Java正则表达式的使用方法,涵盖语法细节、核心类方法、高级特性及实战案例,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录一、正则表达式语法详解1. 基础字符匹配2. 字符类([]定义)3. 量词(控制匹配次数)4. 边

Java Scanner类解析与实战教程

《JavaScanner类解析与实战教程》JavaScanner类(java.util包)是文本输入解析工具,支持基本类型和字符串读取,基于Readable接口与正则分隔符实现,适用于控制台、文件输... 目录一、核心设计与工作原理1.底层依赖2.解析机制A.核心逻辑基于分隔符(delimiter)和模式匹

Java中的stream流分组示例详解

《Java中的stream流分组示例详解》Java8StreamAPI以函数式风格处理集合数据,支持分组、统计等操作,可按单/多字段分组,使用String、Map.Entry或Java16record... 目录什么是stream流1、根据某个字段分组2、按多个字段分组(组合分组)1、方法一:使用 Stri

Java+AI驱动实现PDF文件数据提取与解析

《Java+AI驱动实现PDF文件数据提取与解析》本文将和大家分享一套基于AI的体检报告智能评估方案,详细介绍从PDF上传、内容提取到AI分析、数据存储的全流程自动化实现方法,感兴趣的可以了解下... 目录一、核心流程:从上传到评估的完整链路二、第一步:解析 PDF,提取体检报告内容1. 引入依赖2. 封装

使用Spring Cache本地缓存示例代码

《使用SpringCache本地缓存示例代码》缓存是提高应用程序性能的重要手段,通过将频繁访问的数据存储在内存中,可以减少数据库访问次数,从而加速数据读取,:本文主要介绍使用SpringCac... 目录一、Spring Cache简介核心特点:二、基础配置1. 添加依赖2. 启用缓存3. 缓存配置方案方案

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.

深度剖析SpringBoot日志性能提升的原因与解决

《深度剖析SpringBoot日志性能提升的原因与解决》日志记录本该是辅助工具,却为何成了性能瓶颈,SpringBoot如何用代码彻底破解日志导致的高延迟问题,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言第一章:日志性能陷阱的底层原理1.1 日志级别的“双刃剑”效应1.2 同步日志的“吞吐量杀手”

Spring创建Bean的八种主要方式详解

《Spring创建Bean的八种主要方式详解》Spring(尤其是SpringBoot)提供了多种方式来让容器创建和管理Bean,@Component、@Configuration+@Bean、@En... 目录引言一、Spring 创建 Bean 的 8 种主要方式1. @Component 及其衍生注解