6 Star 72 Fork 28

JustryDeng / notebook

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
[05]动态注册controller.md 8.41 KB
一键复制 编辑 原始数据 按行查看 历史
邓沙利文 提交于 2022-08-03 17:43 . 优化author

动态注册controller

动态注册controller

步骤概述

  • 第一步:利用org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition将类注册为spring bean
  • 第二步:利用org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#detectHandlerMethods(java.lang.Object),将spring-bean解析为controller

代码示例

  • 工具类SpringRegister

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.beans.factory.support.BeanDefinitionBuilder;
    import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.util.StringUtils;
    import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
    import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    /**
     * spring 注册器
     *
     * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
     * @since 2022/6/28 13:31
     */
    @Slf4j
    public final class SpringRegister {
        
        private SpringRegister() {
            throw new UnsupportedOperationException("non-support create SpringRegister instance.");
        }
        
        /**
         * 注册spring bean
         *
         * @see SpringRegister#registerBean(ApplicationContext, Class, String, String)
         */
        public static String registerBean(ApplicationContext applicationContext, Class<?> clazz) {
            String beanName = StringUtils.uncapitalize(clazz.getSimpleName());
            beanName = StringUtils.uncapitalize(beanName);
            return registerBean(applicationContext, clazz, beanName, "singleton");
        }
        
        /**
         * 注册spring bean
         *
         * @see SpringRegister#registerBean(ApplicationContext, Class, String, String)
         */
        public static String registerBean(ApplicationContext applicationContext, Class<?> clazz, String beanName) {
            return registerBean(applicationContext, clazz, beanName, "singleton");
        }
        
        /**
         * 注册spring bean
         *
         * @param applicationContext
         *         spring上下文
         * @param clazz
         *         要注册的class
         * @param beanName
         *         bean name
         * @param scope
         *         作用域
         *
         * @return bean name
         */
        public static String registerBean(ApplicationContext applicationContext, Class<?> clazz, String beanName,
                                          String scope) {
            Object bean = null;
            try {
                bean = applicationContext.getBean(beanName);
            } catch (Exception e) {
                // ignore
            }
            
            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
            BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
            // 设置当前bean的作用域
            beanDefinition.setScope(scope);
            // 将applicationContext转换为ConfigurableApplicationContext
            ConfigurableApplicationContext configurableApplicationContext =
                    (ConfigurableApplicationContext) applicationContext;
            // 获取bean工厂并转换为DefaultListableBeanFactory
            DefaultListableBeanFactory defaultListableBeanFactory =
                    (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();
            if (bean != null) {
                log.warn("A bean with name '" + beanName + "' has already been defined. It is '" + bean + "'. We try to "
                        + "overriding it with bean '" + beanDefinition + "'.");
            }
            defaultListableBeanFactory.registerBeanDefinition(beanName, beanDefinition);
            log.debug("register bean '" + beanName + "' success.");
            return beanName;
        }
        
        /**
         * 将指定bean解析controller bean
         * <br>
         * 核心是利用{@link AbstractHandlerMethodMapping#detectHandlerMethods(java.lang.Object)},将spring-bean解析为controller
         *
         * @param applicationContext
         *         spring上下文
         * @param beanName
         *         要解析的spring bean
         */
        public static void registerController(ApplicationContext applicationContext, String beanName) {
            // step1. 检查beanName存在
            Object bean = null;
            try {
                bean = applicationContext.getBean(beanName);
            } catch (Exception e) {
                // ignore
            }
            if (bean == null) {
                throw new RuntimeException("non-exist spring bean whose name  is [" + beanName + "]. Please register it "
                        + "first.");
            }
            
            // step2. 将beanName解析为controller
            try {
                RequestMappingHandlerMapping requestMappingHandlerMapping =
                        applicationContext.getBean(RequestMappingHandlerMapping.class);
                Method method =
                        requestMappingHandlerMapping.getClass().getSuperclass().getSuperclass().getDeclaredMethod(
                                "detectHandlerMethods", Object.class);
                boolean accessible = method.isAccessible();
                method.setAccessible(true);
                method.invoke(requestMappingHandlerMapping, beanName);
                method.setAccessible(accessible);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException("registerController occur exception.", e);
            }
            log.debug("register controller-bean '" + beanName + "' success.");
        }
    }
  • 要动态注册的controller

    import org.springframework.http.MediaType;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class NormalController {
        
        
        @GetMapping("/fa")
        public ResponseEntity<Map<String, Object>> methodAbc(@RequestParam("name") String name,
                                                             @RequestParam("age") Integer age) {
            Map<String, Object> data = new HashMap<>(4);
            data.put("name", name);
            data.put("age", age);
            return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(data);
        }
        
    }
  • 进行注册

    import com.example.registercontroller.register.NormalController;
    import com.example.registercontroller.register.SpringRegister;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.ApplicationArguments;
    import org.springframework.boot.ApplicationRunner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ApplicationContext;
    
    @SpringBootApplication
    public class RegisterControllerApplication implements ApplicationRunner {
        
        @Autowired
        ApplicationContext applicationContext;
        
        public static void main(String[] args) {
            SpringApplication.run(RegisterControllerApplication.class, args);
        }
        
        @Override
        public void run(ApplicationArguments args) throws Exception {
            // 第一步:利用`org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition`将类注册为spring bean
            String beanName = SpringRegister.registerBean(applicationContext, NormalController.class);
            // 第二步:利用`org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#detectHandlerMethods(java.lang.Object)`,将spring-bean解析为controller
            SpringRegister.registerController(applicationContext, beanName);
        }
    }
  • 启动项目,访问测试

    1656400555762

1
https://gitee.com/JustryDeng/notebook.git
git@gitee.com:JustryDeng/notebook.git
JustryDeng
notebook
notebook
master

搜索帮助