Spring初始化后加载Spring Boot控制器

时间:2017-11-17 17:08:29

标签: java spring spring-boot groovy

我们的Groovy应用程序通过在运行时加载代码来工作。它是一个多租户Web弹簧启动应用程序,包含一些控制器,一些简单的DI,通常的东西。

每个租户都通过外部代码添加到我们的应用程序,外部代码仅在运行时已知。它大致以“插件”方式工作。能够在运行时加载代码使我们能够随意添加,更新和删除这些插件/租户,这在我们的上下文中都是有意义的。这些租户经常被更改,每次我们更改它们时重新启动我们的主应用程序是不可行的。因此,在运行时加载代码的方法对我们来说非常有用。我会稍微交替使用tenant和plugin这两个词,其中插件只是指与租户相关的外部代码。

现在我们使用类似的东西加载这个Groovy代码:

GroovyClassLoader classLoader = new GroovyClassLoader()
classLoader.addClasspath(sourceDirectory)
Class clazz = classLoader.loadClass(pluginMainClass)
return clazz.newInstance()

返回的类型没有Spring的东西,没有注释,它工作得很好,每个人都很开心,生活也很美好。我们的应用程序知道如何存储和使用返回的实例。

但是,其中一个租户需要一个控制器。基本上我想将一些控制器从外部插件代码导入到主应用程序中。

主应用程序已经有一些控制器。我们需要的是在主应用程序中添加另一个控制器。包含这种控制器的Groovy代码只在运行时才知道(我们告诉应用程序在哪里找到源代码,因此我们不能只添加依赖项。

我尝试过的是在插件项目中声明一个具有以下代码的新类:

@Configuration
@Import(ThePluginController)
class ThePluginConfiguration {

}

控制器可能是正确的:

@Controller
@Slf4j
class PanvelController {
    @RequestMapping(path="the-plugin/index", method = RequestMethod.GET)
    def index(Model model){
      return "index"
    }
}

主项目会加载插件:

void loadConfiguration(ApplicationContext context, ...) 
{
    Class clazz = ... get ThePluginConfiguration class object

    AutowireCapableBeanFactory autowire = context.getAutowireCapableBeanFactory()
    BeanDefinitionRegistry registry = (BeanDefinitionRegistry) autowire
    BeanDefinition definition = new RootBeanDefinition(clazz, Autowire.BY_TYPE.value(), true)
    registry.registerBeanDefinition(clazz.name, definition)
}

然而,没有任何反应。控制器根本没有注册,我可能对东西很困惑。可能我发布的代码没有做任何有用的事情,所以我正在寻求帮助。

应该发生的是,在注册控制器时,它应该开始接受对它们映射到的URL的请求。并在日志中显示类似的内容:

2017-11-17 14:52:42.561  INFO 1692 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/the-plugin/index],methods=[GET]}" onto (package/method) ....

此人正在尝试做同样的事情:Spring boot: Add new endpoints at runtime

我还看到其他一些建议像这样的答案,但对我不起作用:http://davidwelch.co/java-stack/programmatically-add-controllers-to-spring-mvc

我是Spring的新手,所以我不确切地知道我的问题是什么。是否有可能实现这一目标?

0 个答案:

没有答案