Spring 如何解决春季的双bean冲突

Spring 如何解决春季的双bean冲突,spring,spring-boot,dependency-injection,Spring,Spring Boot,Dependency Injection,我试图同时使用两个库,GraphQL和Jmix 我使用Intellij的新项目向导(安装了Jmix插件)创建了Jmix项目,然后使用标准GraphQL spring启动程序将GraphQL添加到Gradle中。然后我编写了一个模式和解析器bean 但在启动期间,会引发异常,因为WebSocket端点/订阅在Tomcat上注册了两次。(我尝试使用应用程序属性graphql.servlet.subscriptions.websocket.path更改端点,但这不是问题所在。) 经过一些挖掘,我发现g

我试图同时使用两个库,GraphQL和Jmix

我使用Intellij的新项目向导(安装了Jmix插件)创建了Jmix项目,然后使用标准GraphQL spring启动程序将GraphQL添加到Gradle中。然后我编写了一个模式和解析器bean

但在启动期间,会引发异常,因为WebSocket端点/订阅在Tomcat上注册了两次。(我尝试使用应用程序属性graphql.servlet.subscriptions.websocket.path更改端点,但这不是问题所在。)

经过一些挖掘,我发现graphql spring boot autoconfigure和JMIXUI starter中的类都注册了一个ServerEndpointExporter bean,这是不应该发生的

以下是graphql的代码:

@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(ServerContainer.class)
public ServerEndpointExporter serverEndpointExporter() {
   return new ServerEndpointExporter();
}
这里是Jmix的:

@Bean
public ServerEndpointExporter websocketEndpointDeployer() {
    return new VaadinWebsocketEndpointExporter();
}
GraphQL标记为ConditionalOnMissingBean,但在另一个之前注册,因此不会触发该条件

如何禁用这两个bean中的一个,或设置它们的优先级

通过完全禁用GraphQL的websocket服务,我成功地解决了这个问题:

graphql.servlet.websocket.enabled = false

但我想知道一般情况下如何解决此类问题。

不幸的是,这些配置似乎有问题,因此您无法以类似Spring的方式“惯用”地执行某些操作

我所能想到的所有解决方案都是比较变通的,解决这个问题的最好方法可能是在相应的团队中打开一个缺陷,这样他们就可以引入一个属性,允许以两种方式禁用配置。也许他们已经这么做了,谁知道呢

至于可能的解决办法:

  • 使用属性:
    graphql.servlet.websocket.enabled=false
    它将禁用graphql配置。您将能够自己重新定义所需的bean。例如,如果需要,只定义:
    ServerEndpointRegistration
    ServerEndpointExporter
    bean。注意-我还没有检查graphql库的源文件,可能这个属性在其他地方使用过

  • 尝试重新定义您想要/不想要加载的bean的bean定义。这可以通过BeanFactoryPostProcessor完成:


  • 只是澄清一下——在应用程序启动期间,当bean定义已经解析,但在实际注入发生之前,spring会调用bean factory后处理器。

    请您链接到GraphQLWebAutoConfiguration和VaadinAutoConfiguration的源代码,以解决此问题?@MarkBramnik I已更新库(我没有使用最新版本)和我添加的链接。谢谢,请查看我的答案。我知道这听起来像是解决办法,但在这种情况下,这是我能建议的最好办法了……非常感谢!
    @Component
    public class SampleBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
         // find the bean definition of the bean you need and try to:
         // - set "primary" on it
         String bdName = ... here put the name of the bean you want to fine-tune
         BeanDefinition beanDefinition =  beanFactory.getBeanDefinition(bdName);
         beanDefinition.setPrimary(true);
         // ... or ... 
         // - remove it altogether from the application context (bean factory)
         ((BeanDefinitionRegistry)beanFactory).removeBeanDefinition(bdName);