<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
部分場景下可能需要下載遠端jar包,然後註冊jar包中的Bean和Controller
這裡的Bean 一般特指 Service層的服務類,Controller本質上也是Bean
這裡用了一些 hutool的工具類,hutools是一個不錯的基礎工具集。
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; /** * 動態註冊登出Spring Bean * * @author guzt */ @SuppressWarnings("unused") public class DynamicRegistUtil { /** * 動態註冊Bean * * @param beanName bean名稱 * @param targetClass bean對應的類 */ public static void registerBeanDefinition(String beanName, Class<?> targetClass) { ApplicationContext applicationContext = SpringUtil.getApplicationContext(); //獲取BeanFactory DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory(); //建立bean資訊. BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(targetClass); //動態註冊bean. defaultListableBeanFactory.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition()); } /** * 動態解除安裝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); } /** * 動態註冊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; } //註冊Controller Method method = requestMappingHandlerMapping.getClass().getSuperclass().getSuperclass(). getDeclaredMethod("detectHandlerMethods", Object.class); //將private改為可使用 method.setAccessible(true); method.invoke(requestMappingHandlerMapping, controllerBeanName); } } /** * 動態去掉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); } } }
建立一個maven專案(dynamic-regist-bean),裡面主要引入spring-boot-starter-web即可
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
建立一個service測試類
package org.example.service; public interface DynamicRegistService { void serviceDo(); }
建立介面對應的實現類,上面無需@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動態註冊的Bean dynamicRegistServiceImpl中的 serviceDo 無參方法執行完成..."); } }
建立一個controller測試類,類上面無需 @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請求測試成功, 傳遞引數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請求測試成功, 傳輸的引數id:" + id); map.put("data", ""); return map; } }
編譯打包
> maven clean package
mavne打包命令生成 dynamic-regist-bean.jar
另外一個SpringBoot中建立測試介面
假設存取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 = "動態註冊Bean、Controller測試") @RestController @RequestMapping("dynamicRegistTestController") public class DynamicRegistTestController { private static final Logger logger = LoggerFactory.getLogger(DynamicRegistTestController.class); /** * 模擬從遠端下載準備要註冊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(); // 準備要註冊的Bean類名 String className = "org.example.service.impl.DynamicRegistServiceImpl"; // 準備要註冊的Bean名稱 String beanName = "dynamicRegistServiceImpl"; // 註冊完成後呼叫Bean的測試方法 String invokeMethod = "serviceDo"; Class<?> targetClass = ClassLoaderUtil.loadClass(jarFile, className); logger.info("本次要註冊的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("解除安裝結果:{}", SpringUtil.getApplicationContext().containsBean(beanName) ? "失敗" : "成功"); return ResponseVO.success(); } @GetMapping("registController") public ResponseVO<NoBody> registController() throws Exception { File jarFile = getRmoteJarFile(); // 準備要註冊的Bean類名 String className = "org.example.controller.DynamicRegistController"; // 準備要註冊的Bean名稱 String beanName = "dynamicRegistController"; Class<?> targetClass = ClassLoaderUtil.loadClass(jarFile, className); logger.info("本次要註冊的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("解除安裝結果:{}", SpringUtil.getApplicationContext().containsBean(beanName) ? "失敗" : "成功"); return ResponseVO.success(); } }
存取: http://localhost:8081/dynamicRegistTestController/registBean
返回:
{"code":"0","message":"SUCCESS","data":null}
紀錄檔:
[http-nio-8081-exec-1] c.g.c.DynamicRegistTestController : 本次要註冊的bean className = org.example.service.impl.DynamicRegistServiceImpl
[http-nio-8081-exec-1] o.e.s.impl.DynamicRegistServiceImpl : Spring動態註冊的Bean dynamicRegistServiceImpl中的 serviceDo 無參方法執行完成...
存取:http://localhost:8081/dynamicRegistTestController/registController
返回:
{"code":"0","message":"SUCCESS","data":null}
紀錄檔:
[http-nio-8081-exec-5] c.g.c.DynamicRegistTestController : 本次要註冊的controller className = org.example.controller.DynamicRegistController
測試Controller 是否真的註冊成功:
存取: http://localhost:8081/dynamicRegistController/getTest/aaaa 返回:
{"msg":"GET請求測試成功, 傳輸的引數id:aaaa","data":"","code":"0"}
存取:http://localhost:8081/dynamicRegistTestController/unRegistController
然後重新存取: http://localhost:8081/dynamicRegistController/getTest/aaaa
返回:404錯誤 ,說明登出成功!
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).
到此這篇關於SpringBean和Controller實現動態註冊與登出過程詳細講解的文章就介紹到這了,更多相關SpringBean動態註冊與登出內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45