一文詳解SpringBoot中控制器的動態(tài)注冊與卸載
在項目開發(fā)中,通過動態(tài)注冊和卸載控制器功能,可以根據(jù)業(yè)務場景和項目需要實現(xiàn)功能的動態(tài)增加、刪除,提高系統(tǒng)的靈活性和可擴展性。
本文將介紹如何在 SpringBoot 中實現(xiàn)控制器的動態(tài)注冊和卸載。
項目結構
src
└── main
├── java
│ └── com
│ └── example
│ ├── DynamicControllerApplication.java
│ ├── controller
│ │ ├── DemoController.java
│ │ └── DynamicControllerRegistry.java
│ │ └── DynamicController.java
│ │ └── ControllerManagement.java
│ └── config
│ └── WebConfig.java
└── resources
└── application.properties
1. 創(chuàng)建 Spring Boot 啟動類
首先,創(chuàng)建一個啟動類 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. 創(chuàng)建一個測試控制器
接下來,我們創(chuàng)建一個控制器 DemoController.java,該控制器將返回簡單的字符串響應。
// 動態(tài)控制器注解
@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.annotation.RestController;
@RestController
@RequestMapping("/demo")
@DynamicController(startupRegister = false)
public class DemoController {
@GetMapping("/hello")
public String hello() {
return "Hello from Dynamic Controller!";
}
}3. 創(chuàng)建動態(tài)控制器注冊類
然后,我們創(chuàng)建一個 DynamicControllerRegistry.java 類,用于動態(tài)注冊和卸載控制器。
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
private ApplicationContext applicationContext;
@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;
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 method = ReflectUtil.getMethod(controllerClass,methodName);
RequestMapping methodMapping = AnnotatedElementUtils.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. 創(chuàng)建 Web 配置類
創(chuàng)建配置類 WebConfig.java ,實現(xiàn)項目啟動時將不需要注冊的控制器進行卸載。
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. 創(chuàng)建動態(tài)控制器注冊和卸載控制器
創(chuàng)建一個新的控制器 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,因為控制器已被卸載
結論
通過以上步驟,我們實現(xiàn)了在 Spring Boot 中動態(tài)注冊和卸載控制器的功能。
這樣的實現(xiàn)能夠根據(jù)實際需求動態(tài)增減功能。
到此這篇關于一文詳解SpringBoot中控制器的動態(tài)注冊與卸載的文章就介紹到這了,更多相關SpringBoot控制器注冊與卸載內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java Swing組件下拉菜單控件JComboBox用法示例
這篇文章主要介紹了Java Swing組件下拉菜單控件JComboBox用法,結合具體實例形式分析了Swing組件下拉菜單控件JComboBox的具體定義、使用方法及相關使用注意事項,需要的朋友可以參考下2017-11-11
SpringBoot+EasyExcel實現(xiàn)自定義復雜樣式導入導出
這篇文章主要為大家詳細介紹了SpringBoot如何結果EasyExcel實現(xiàn)自定義復雜樣式導入導出功能,文中的示例代碼講解詳細,感興趣的小伙伴可以了解下2025-07-07
業(yè)務系統(tǒng)的Prometheus實踐示例詳解
這篇文章主要為大家介紹了業(yè)務系統(tǒng)的Prometheus實踐示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-04-04
Spring實現(xiàn)類私有方法的幾個問題(親測通用解決方案)
現(xiàn)實的業(yè)務場景中,可能需要對Spring的實現(xiàn)類的私有方法進行測試。本文給大家分享Spring實現(xiàn)類私有方法面臨的幾個問題及解決方案,感興趣的朋友跟隨小編一起看看吧2021-06-06

