中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringBean和Controller如何實現動態注冊與注銷

發布時間:2023-02-10 09:12:17 來源:億速云 閱讀:114 作者:iii 欄目:開發技術

這篇文章主要講解了“SpringBean和Controller如何實現動態注冊與注銷”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“SpringBean和Controller如何實現動態注冊與注銷”吧!

部分場景下可能需要下載遠程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();
    }
}

測試結果

注冊Service

訪問: 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 無參方法執行完成...

注冊controller

訪問: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"}

注銷Controller

訪問: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和Controller如何實現動態注冊與注銷這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

外汇| 宁安市| 都兰县| 苏尼特右旗| 牙克石市| 莫力| 萍乡市| 龙江县| 吐鲁番市| 钟祥市| 屏东县| 宜城市| 东港市| 沙坪坝区| 玉龙| 东阳市| 伊川县| 武胜县| 楚雄市| 兴隆县| 九台市| 永康市| 怀仁县| 宜兰市| 岚皋县| 佛冈县| 广州市| 新干县| 长春市| 富源县| 常宁市| 上虞市| 宝山区| 石景山区| 云龙县| 栾川县| 康保县| 腾冲县| 闻喜县| 通海县| 南投县|