如何解决 Spring 双豆冲突

jfewjypa  于 2021-07-13  发布在  Java
关注(0)|答案(1)|浏览(424)

我尝试同时使用两个库,graphql和jmix。
我使用intellij的新项目向导(安装了jmix插件)创建了jmix项目,然后使用标准graphql spring boot starter将graphql添加到gradle中。然后我编写了一个模式和解析器bean。
但在启动过程中,会引发异常,因为websocket端点/订阅在tomcat上注册了两次(我尝试使用应用程序属性graphql.servlet.subscriptions.websocket.path更改端点,但这不是问题所在。)
经过一番挖掘,我发现graphql spring boot autoconfigure中的graphqlwebsocketautoconfiguration类和jmix ui starter中的vaadinautoconfiguration类都在注册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

但我想知道如何解决这类问题。

ruyhziif

ruyhziif1#

不幸的是,这些配置看起来像是bug,所以没有什么东西可以像spring那样“惯用”地执行。
我能想到的所有解决方案都是解决方法,解决这个问题的最好方法可能是在相应的团队中打开一个缺陷,这样他们就可以引入一个属性,允许以两种方式禁用配置。好吧,也许他们已经这么做了,谁知道呢。
至于可能的解决办法:
使用属性: graphql.servlet.websocket.enabled=false 它将禁用graphql配置。你可以自己重新定义你需要的豆子。例如,仅定义: ServerEndpointRegistration 以及 ServerEndpointExporter 如果你需要的话。注意-我还没有检查graphql库的源文件,可能这个属性在其他地方使用。
尝试重新定义您想要/不想要加载的bean的bean定义。这可以通过beanfactorypostprocessor完成:

@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);

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

相关问题