SpringBoot动态添加/删除Controller

4,983 阅读2分钟

前言

一般情况下写Controller都是先在类上声明一个@RestController或是@Controller,然后在方法上加上url路径即可,其实也可以动态注册的,不用写@Controller,只写方法,可以在系统启动后,动态注册,动态移除。

SpringBoot最终会把"请求映射"封装在一个map中,所以我们也可以直接往这个map中存信息即可,这里的"请求"就是请求地址的url,"映射"就是吧这个url的响应交给某个方法。

所以我们需要两个信息,url和具体的响应方法。

SpringBoot把他封装为RequestMappingInfo,那首先要做的就是构建RequestMappingInfo,但是他的构造方法非常的麻烦,好在提供了内部Builder类。

就像下面这样,其中的test就是规定这个请求的url,方法为get。

val requestMappingInfo = RequestMappingInfo
    .paths("test")
    .methods(RequestMethod.GET)
    .build()

下面就是通过RequestMappingHandlerMapping添加到内部的map中,RequestMappingHandlerMapping可以通过@Inject自动注入,也可以通过ApplicationContext.getBean获取。

如下面所示,调用registerMapping方法时,第二个参数是具体响应数据的方法所在的类的bean名称。

也就是方法所在类必须被SpringBoot容器管理,这也好理解,因为在通过反射调用方法时候,总的有个他的实例对象吧,否则怎么调?

fun main(args: Array<String>) {
    var application = runApplication<CoolDeployApplication>(*args)
    var bean = application.getBean(RequestMappingHandlerMapping::class.java)

    val requestMappingInfo = RequestMappingInfo
        .paths("test")
        .methods(RequestMethod.GET)
        .build()

    bean.registerMapping(requestMappingInfo, "testRequest", TestRequest::class.java.getDeclaredMethod("test",Int::class.java))
}

先简单使用@Component,最后的bean名称就是testRequest。

@Component
class TestRequest {
    @ResponseBody
    fun test(@RequestParam("id")id:Int): Any {
        return "${id}"
    }
}

但是也可以通过@Bean来管理,这样,最后的TestRequest类上不需要加任何注解。

@SpringBootApplication
class CoolDeployApplication : SpringApplicationRunListener {
    @Bean
    fun testRequest(): TestRequest {
        return TestRequest();
    }
}

这样就可以测试了。

image.png

用下面代码可以移除所有Controller

bean.handlerMethods.forEach { t, u ->
    bean.unregisterMapping(t)
}