一文詳解SpringBoot中控制器的動態(tài)注冊與卸載
在項(xiàng)目開發(fā)中,通過動態(tài)注冊和卸載控制器功能,可以根據(jù)業(yè)務(wù)場景和項(xiàng)目需要實(shí)現(xiàn)功能的動態(tài)增加、刪除,提高系統(tǒng)的靈活性和可擴(kuò)展性。
本文將介紹如何在 SpringBoot 中實(shí)現(xiàn)控制器的動態(tài)注冊和卸載。
項(xiàng)目結(jié)構(gòu)
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)建一個(gè)啟動類 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)建一個(gè)測試控制器
接下來,我們創(chuàng)建一個(gè)控制器 DemoController.java
,該控制器將返回簡單的字符串響應(yīng)。
// 動態(tài)控制器注解 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface DynamicController { // 啟動時(shí)注冊 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)建一個(gè) 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
,實(shí)現(xiàn)項(xiàng)目啟動時(shí)將不需要注冊的控制器進(jì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; } // 默認(rèn)不需要注冊的controller,需要在啟動時(shí)注銷掉 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)建一個(gè)新的控制器 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. 啟動服務(wù)
2. 訪問 http://localhost:8080/demo/hello ,此時(shí)應(yīng)該是404,因?yàn)闆]有注冊控制器
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>,此時(shí)應(yīng)該是404,因?yàn)榭刂破饕驯恍遁d
結(jié)論
通過以上步驟,我們實(shí)現(xiàn)了在 Spring Boot 中動態(tài)注冊和卸載控制器的功能。
這樣的實(shí)現(xiàn)能夠根據(jù)實(shí)際需求動態(tài)增減功能。
到此這篇關(guān)于一文詳解SpringBoot中控制器的動態(tài)注冊與卸載的文章就介紹到這了,更多相關(guān)SpringBoot控制器注冊與卸載內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JDBC操作數(shù)據(jù)庫的增加、刪除、更新、查找實(shí)例分析
這篇文章主要介紹了JDBC操作數(shù)據(jù)庫的增加、刪除、更新、查找方法,以完整實(shí)例形式分析了Java基于JDBC連接數(shù)據(jù)庫及進(jìn)行數(shù)據(jù)的增刪改查等技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10新手學(xué)習(xí)JQuery基本操作和使用案例解析
這篇文章主要介紹了新手學(xué)習(xí)JQuery基本操作和使用案例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02Springboot自定義注解&傳參&簡單應(yīng)用方式
SpringBoot框架中,通過自定義注解結(jié)合AOP可以實(shí)現(xiàn)功能如日志記錄與耗時(shí)統(tǒng)計(jì),首先創(chuàng)建LogController和TimeConsuming注解,并為LogController定義參數(shù),然后,在目標(biāo)方法上應(yīng)用這些注解,最后,使用AspectJ的AOP功能,通過切點(diǎn)表達(dá)式定位這些注解2024-10-10Idea Jrebel 報(bào)錯(cuò):Cannot reactivate,offline 
本文主要介紹了Idea Jrebel 報(bào)錯(cuò):Cannot reactivate,offline seat in use,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06詳解Java如何優(yōu)雅的實(shí)現(xiàn)字典翻譯
當(dāng)我們在Java應(yīng)用程序中需要對字典屬性進(jìn)行轉(zhuǎn)換返回給前端時(shí),如何簡單、方便、并且優(yōu)雅的處理是一個(gè)重要問題。在本文中,我們將介紹如何使用Java中的序列化機(jī)制來優(yōu)雅地實(shí)現(xiàn)字典值的翻譯,從而簡化開發(fā)2023-04-04詳解spring cloud config實(shí)現(xiàn)datasource的熱部署
這篇文章主要介紹了詳解spring cloud config實(shí)現(xiàn)datasource的熱部署,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01