SpringBean和Controller實(shí)現(xiàn)動(dòng)態(tài)注冊(cè)與注銷過(guò)程詳細(xì)講解
部分場(chǎng)景下可能需要下載遠(yuǎn)程jar包,然后注冊(cè)jar包中的Bean和Controller
說(shuō)明
這里的Bean 一般特指 Service層的服務(wù)類,Controller本質(zhì)上也是Bean
注冊(cè)和注銷工具類
這里用了一些 hutool的工具類,hutools是一個(gè)不錯(cuò)的基礎(chǔ)工具集。
package cn.guzt.utils; import cn.hutool.extra.spring.SpringUtil; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; import org.springframework.web.servlet.mvc.method.RequestMappingInfo; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import java.lang.reflect.Method; /** * 動(dòng)態(tài)注冊(cè)注銷Spring Bean * * @author guzt */ @SuppressWarnings("unused") public class DynamicRegistUtil { /** * 動(dòng)態(tài)注冊(cè)Bean * * @param beanName bean名稱 * @param targetClass bean對(duì)應(yīng)的類 */ public static void registerBeanDefinition(String beanName, Class<?> targetClass) { ApplicationContext applicationContext = SpringUtil.getApplicationContext(); //獲取BeanFactory DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory(); //創(chuàng)建bean信息. BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(targetClass); //動(dòng)態(tài)注冊(cè)bean. defaultListableBeanFactory.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition()); } /** * 動(dòng)態(tài)卸載Bean * * @param beanName bean名稱 */ public static void unRegisterBeanDefinition(String beanName) { ApplicationContext applicationContext = SpringUtil.getApplicationContext(); if (!applicationContext.containsBean(beanName)) { return; } //獲取BeanFactory DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory(); defaultListableBeanFactory.removeBeanDefinition(beanName); } /** * 動(dòng)態(tài)注冊(cè)Controller * * @param controllerBeanName controller的beanName * @throws Exception 反射異常 */ public static void registerController(String controllerBeanName) throws Exception { final RequestMappingHandlerMapping requestMappingHandlerMapping = SpringUtil.getBean(RequestMappingHandlerMapping.class); if (requestMappingHandlerMapping != null) { Object controller = SpringUtil.getBean(controllerBeanName); if (controller == null) { return; } //注冊(cè)Controller Method method = requestMappingHandlerMapping.getClass().getSuperclass().getSuperclass(). getDeclaredMethod("detectHandlerMethods", Object.class); //將private改為可使用 method.setAccessible(true); method.invoke(requestMappingHandlerMapping, controllerBeanName); } } /** * 動(dòng)態(tài)去掉Controller的Mapping * * @param controllerBeanName controller的beanName */ public static void unregisterController(String controllerBeanName) { final RequestMappingHandlerMapping requestMappingHandlerMapping = SpringUtil.getBean("requestMappingHandlerMapping"); if (requestMappingHandlerMapping != null) { Object controller = SpringUtil.getBean(controllerBeanName); if (controller == null) { return; } final Class<?> targetClass = controller.getClass(); ReflectionUtils.doWithMethods(targetClass, method -> { Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass); try { Method createMappingMethod = RequestMappingHandlerMapping.class. getDeclaredMethod("getMappingForMethod", Method.class, Class.class); createMappingMethod.setAccessible(true); RequestMappingInfo requestMappingInfo = (RequestMappingInfo) createMappingMethod.invoke(requestMappingHandlerMapping, specificMethod, targetClass); if (requestMappingInfo != null) { requestMappingHandlerMapping.unregisterMapping(requestMappingInfo); } } catch (Exception e) { e.printStackTrace(); } }, ReflectionUtils.USER_DECLARED_METHODS); } } }
編寫測(cè)試用例
創(chuàng)建一個(gè)maven項(xiàng)目(dynamic-regist-bean),里面主要引入spring-boot-starter-web即可
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
創(chuàng)建一個(gè)service測(cè)試類
package org.example.service; public interface DynamicRegistService { void serviceDo(); }
創(chuàng)建接口對(duì)應(yīng)的實(shí)現(xiàn)類,上面無(wú)需@Service 注解
package org.example.service.impl; import lombok.extern.slf4j.Slf4j; import org.example.service.DynamicRegistService; @Slf4j public class DynamicRegistServiceImpl implements DynamicRegistService { @Override public void serviceDo() { log.info("Spring動(dòng)態(tài)注冊(cè)的Bean dynamicRegistServiceImpl中的 serviceDo 無(wú)參方法執(zhí)行完成..."); } }
創(chuàng)建一個(gè)controller測(cè)試類,類上面無(wú)需 @Controller注解
package org.example.controller; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; @ResponseBody @RequestMapping("dynamicRegistController") public class DynamicRegistController { @PostMapping("postTest") public Map<String, Object> postTest(@RequestBody Map<String, Object> params) { Map<String, Object> map = new HashMap<>(4); map.put("code", "0"); map.put("msg", "POST請(qǐng)求測(cè)試成功, 傳遞參數(shù)params:" + params.toString()); map.put("data", ""); return map; } @GetMapping("getTest/{id}") public Map<String, Object> getTest(@PathVariable("id") String id) { Map<String, Object> map = new HashMap<>(4); map.put("code", "0"); map.put("msg", "GET請(qǐng)求測(cè)試成功, 傳輸?shù)膮?shù)id:" + id); map.put("data", ""); return map; } }
編譯打包
> maven clean package
mavne打包命令生成 dynamic-regist-bean.jar
另外一個(gè)SpringBoot中創(chuàng)建測(cè)試接口
假設(shè)訪問(wèn)BaseUrl為: http://localhost:8081
import cn.guzt.utils.DynamicRegistUtil; import cn.hutool.core.util.ClassLoaderUtil; import cn.hutool.core.util.ReflectUtil; import cn.hutool.extra.spring.SpringUtil; import com.middol.starter.common.pojo.vo.NoBody; import com.middol.starter.common.pojo.vo.ResponseVO; import io.swagger.annotations.Api; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.io.File; @Api(tags = "動(dòng)態(tài)注冊(cè)Bean、Controller測(cè)試") @RestController @RequestMapping("dynamicRegistTestController") public class DynamicRegistTestController { private static final Logger logger = LoggerFactory.getLogger(DynamicRegistTestController.class); /** * 模擬從遠(yuǎn)程下載準(zhǔn)備要注冊(cè)Bean的jar文件 * * @return jar文件 */ private File getRmoteJarFile() { return new File("E:/IDEA_HOME/dynamic-regist-bean/dynamic-regist-bean/target/dynamic-regist-bean.jar"); } @GetMapping("registBean") public ResponseVO<NoBody> registBean() { File jarFile = getRmoteJarFile(); // 準(zhǔn)備要注冊(cè)的Bean類名 String className = "org.example.service.impl.DynamicRegistServiceImpl"; // 準(zhǔn)備要注冊(cè)的Bean名稱 String beanName = "dynamicRegistServiceImpl"; // 注冊(cè)完成后調(diào)用Bean的測(cè)試方法 String invokeMethod = "serviceDo"; Class<?> targetClass = ClassLoaderUtil.loadClass(jarFile, className); logger.info("本次要注冊(cè)的bean className = {}", targetClass.getName()); DynamicRegistUtil.registerBeanDefinition(beanName, targetClass); Object object = SpringUtil.getBean(beanName); ReflectUtil.invoke(object, invokeMethod); return ResponseVO.success(); } @GetMapping("unRegistBean") public ResponseVO<NoBody> unRegistBean() { String beanName = "dynamicRegistServiceImpl"; logger.info("本次要卸載的bean beanName = {}", beanName); DynamicRegistUtil.unRegisterBeanDefinition(beanName); logger.info("卸載結(jié)果:{}", SpringUtil.getApplicationContext().containsBean(beanName) ? "失敗" : "成功"); return ResponseVO.success(); } @GetMapping("registController") public ResponseVO<NoBody> registController() throws Exception { File jarFile = getRmoteJarFile(); // 準(zhǔn)備要注冊(cè)的Bean類名 String className = "org.example.controller.DynamicRegistController"; // 準(zhǔn)備要注冊(cè)的Bean名稱 String beanName = "dynamicRegistController"; Class<?> targetClass = ClassLoaderUtil.loadClass(jarFile, className); logger.info("本次要注冊(cè)的controller className = {}", targetClass.getName()); DynamicRegistUtil.registerBeanDefinition(beanName, targetClass); DynamicRegistUtil.registerController(beanName); return ResponseVO.success(); } @GetMapping("unRegistController") public ResponseVO<NoBody> unRegistController() { String beanName = "dynamicRegistController"; logger.info("本次要卸載的Controller beanName = {}", beanName); DynamicRegistUtil.unregisterController(beanName); DynamicRegistUtil.unRegisterBeanDefinition(beanName); logger.info("卸載結(jié)果:{}", SpringUtil.getApplicationContext().containsBean(beanName) ? "失敗" : "成功"); return ResponseVO.success(); } }
測(cè)試結(jié)果
注冊(cè)Service
訪問(wèn): http://localhost:8081/dynamicRegistTestController/registBean
返回:
{"code":"0","message":"SUCCESS","data":null}
日志:
[http-nio-8081-exec-1] c.g.c.DynamicRegistTestController : 本次要注冊(cè)的bean className = org.example.service.impl.DynamicRegistServiceImpl
[http-nio-8081-exec-1] o.e.s.impl.DynamicRegistServiceImpl : Spring動(dòng)態(tài)注冊(cè)的Bean dynamicRegistServiceImpl中的 serviceDo 無(wú)參方法執(zhí)行完成...
注冊(cè)controller
訪問(wèn):http://localhost:8081/dynamicRegistTestController/registController
返回:
{"code":"0","message":"SUCCESS","data":null}
日志:
[http-nio-8081-exec-5] c.g.c.DynamicRegistTestController : 本次要注冊(cè)的controller className = org.example.controller.DynamicRegistController
測(cè)試Controller 是否真的注冊(cè)成功:
訪問(wèn): http://localhost:8081/dynamicRegistController/getTest/aaaa 返回:
{"msg":"GET請(qǐng)求測(cè)試成功, 傳輸?shù)膮?shù)id:aaaa","data":"","code":"0"}
注銷Controller
訪問(wèn):http://localhost:8081/dynamicRegistTestController/unRegistController
然后重新訪問(wèn): http://localhost:8081/dynamicRegistController/getTest/aaaa
返回:404錯(cuò)誤 ,說(shuō)明注銷成功!
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.Tue Feb 07 14:14:52 CST 2023
There was an unexpected error (type=Not Found, status=404).
到此這篇關(guān)于SpringBean和Controller實(shí)現(xiàn)動(dòng)態(tài)注冊(cè)與注銷過(guò)程詳細(xì)講解的文章就介紹到這了,更多相關(guān)SpringBean動(dòng)態(tài)注冊(cè)與注銷內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring?@Conditional通過(guò)條件控制bean注冊(cè)過(guò)程
- 向Spring IOC 容器動(dòng)態(tài)注冊(cè)bean實(shí)現(xiàn)方式
- 解決Springboot全局異常處理與AOP日志處理中@AfterThrowing失效問(wèn)題
- SpringBoot項(xiàng)目使用aop案例詳解
- BeanDefinitionRegistryPostProcessor如何動(dòng)態(tài)注冊(cè)Bean到Spring
- Spring運(yùn)行時(shí)動(dòng)態(tài)注冊(cè)bean的方法
- spring動(dòng)態(tài)注冊(cè)bean?AOP失效原理解析
相關(guān)文章
Java的Spring框架中實(shí)現(xiàn)發(fā)送郵件功能的核心代碼示例
這篇文章主要介紹了Java的Spring框架中實(shí)現(xiàn)發(fā)送郵件功能的核心代碼示例,包括發(fā)送帶附件的郵件功能的實(shí)現(xiàn),需要的朋友可以參考下2016-03-03金三銀四復(fù)工高頻面試題java算法LeetCode396旋轉(zhuǎn)函數(shù)
這篇文章主要為大家介紹了金三銀四復(fù)工高頻面試題之java算法題解LeetCode396旋轉(zhuǎn)函數(shù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Fluent Mybatis實(shí)際開(kāi)發(fā)中的優(yōu)勢(shì)對(duì)比
本文給大家介紹如何通過(guò)IQuery和IUpdate定義強(qiáng)大的動(dòng)態(tài)SQL語(yǔ)句,給大家分享Fluent Mybatis實(shí)際開(kāi)發(fā)中的優(yōu)勢(shì)講解,感興趣的朋友一起看看吧2021-08-08Spring中@RabbitHandler和@RabbitListener的區(qū)別詳析
@RabbitHandler是用于處理消息的方法注解,它與@RabbitListener注解一起使用,這篇文章主要給大家介紹了關(guān)于Spring中@RabbitHandler和@RabbitListener區(qū)別的相關(guān)資料,需要的朋友可以參考下2024-02-02Java中JVM的雙親委派、內(nèi)存溢出、垃圾回收和調(diào)優(yōu)詳解
這篇文章主要介紹了Java中JVM的雙親委派、內(nèi)存溢出、垃圾回收和調(diào)優(yōu)詳解,類加載器是Java虛擬機(jī)(JVM)的一個(gè)重要組成部分,它的主要作用是將類的字節(jié)碼加載到內(nèi)存中,并生成對(duì)應(yīng)的Class對(duì)象,需要的朋友可以參考下2023-07-07IntelliJ IDEA中使用mybatis-generator的示例
這篇文章主要介紹了IntelliJ IDEA中使用mybatis-generator,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04解決Mybatis的@Param()注解導(dǎo)致分頁(yè)失效的問(wèn)題
這篇文章主要介紹了解決Mybatis的@Param()注解導(dǎo)致分頁(yè)失效的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04