【问题标题】:mongodb multi tenacy spel with @Document带有@Document的mongodb多租户拼写
【发布时间】:2013-11-17 10:24:06
【问题描述】:

这与 MongoDB and SpEL Expressions in @Document annotations

这就是我创建 mongo 模板的方式

@Bean
public MongoDbFactory mongoDbFactory() throws UnknownHostException {
    String dbname = getCustid();
    return new SimpleMongoDbFactory(new MongoClient("localhost"), "mydb");
}

@Bean
MongoTemplate mongoTemplate() throws UnknownHostException {
    MappingMongoConverter converter = 
            new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext());
    return new MongoTemplate(mongoDbFactory(), converter);
}

我有一个租户提供者类

@Component("tenantProvider")
public class TenantProvider {

    public String getTenantId() {
      --custome Thread local logic for getting a name
    }
}

还有我的域类

    @Document(collection = "#{@tenantProvider.getTenantId()}_device")
     public class Device {
    -- my fields here
    }

如您所见,我已按照帖子中的说明创建了我的 mongotemplate,但我仍然收到以下错误

线程“main”中的异常 org.springframework.expression.spel.SpelEvaluationException: EL1057E:(pos 1): 上下文中没有注册 bean 解析器来解析对 bean 'tenantProvider' 的访问

我做错了什么?

【问题讨论】:

  • 任何帮助将不胜感激

标签: java spring mongodb spring-data-mongodb spring-el


【解决方案1】:

以上答案对我来说只是部分起作用。

我一直在努力解决同样的问题,最终意识到在某些运行时执行路径下(当 RepositoryFactorySupport 依赖 AbstractMongoQuery 来查询 MongoDB,而不是据我所知在“开箱即用”方法中使用的 SimpleMongoRepository由 SpringData 提供)在 AbstractMongoQuery 中使用的属于 MongoQueryMethod 的 MongoEntityMetadata 类型的元数据对象仅在名为 getEntityInformation() 的方法中更新一次

因为持有对此“有状态”bean 的引用的 MongoQueryMethod 对象似乎被基础设施代码池化/缓存,带有 Spel 的 @Document 注释并不总是有效。

据我所知,作为开发人员,我们只有一个选择,直接从您的 @Repository bean 使用 MongoOperations,以便能够指定在运行时使用 Spel 评估的正确集合名称。

我尝试使用 AOP 来修改此行为,方法是在 MongoEntityMetadata 中设置一个空集合名称,但这无济于事,因为实现 Execution 接口的 AbstractMongoQuery 内部类中的更改也需要按顺序完成检查 MongoEntityMetadata 集合名称是否为空,因此使用不同的 MongoTemplate 方法签名。 MongoTemplate 足够聪明,可以使用其私有方法猜出正确的集合名称

private <T> String determineEntityCollectionName(T obj)

我在 spring 的 jira https://jira.spring.io/browse/DATAMONGO-1043 中创建了一张票

【讨论】:

    【解决方案2】:

    终于知道为什么会出现这个问题了。

    使用 Servlet 3 初始化时,请确保将应用程序上下文添加到 mongo 上下文中,如下所示

        @Autowired
    private ApplicationContext appContext;
    
    public MongoDbFactory mongoDbFactory() throws UnknownHostException {
        return new SimpleMongoDbFactory(new MongoClient("localhost"), "apollo-mongodb");
    }
    
    @Bean
    MongoTemplate mongoTemplate() throws UnknownHostException {
        final MongoDbFactory factory = mongoDbFactory();
    
        final MongoMappingContext mongoMappingContext = new MongoMappingContext();
        mongoMappingContext.setApplicationContext(appContext);
    
        // Learned from web, prevents Spring from including the _class attribute
        final MappingMongoConverter converter = new MappingMongoConverter(factory, mongoMappingContext);
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));
    
        return new MongoTemplate(factory, converter);
    }
    

    检查上下文的自动装配以及 mongoMappingContext.setApplicationContext(appContext);

    通过这两行,我能够正确连接组件以在多租户模式下使用它

    【讨论】:

    • 它可以工作,但是构造函数 MappingMongoConverter(factory, mongoMappingContext) 被标记为已弃用。
    • 你有其他构造函数,它接受一个可以用工厂构造的 DBRefResolver:MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory), mappingContext)。顺便说一句,这个答案很棒,“只需将 applicationContext 设置为 mongoMappingContext”。
    【解决方案3】:

    如果您在相关问题中配置了 mongoTemplate,我唯一能想到的是:

    <context:component-scan base-package="com.tenantprovider.package" />
    

    或者如果你想使用注解:

    @ComponentScan(basePackages = "com.tenantprovider.package")
    

    您可能没有扫描租户提供程序包。

    例如:

    @ComponentScan(basePackages = "com.tenantprovider.package")
    @Document(collection = "#{@tenantProvider.getTenantId()}_device")
    public class Device {
        -- my fields here
    }
    

    【讨论】:

    • 这没有帮助,我添加了组件扫描但同样的错误。一个奇怪的是,如果我在我的配置类中给出 ComponentScan,我会得到一个不同的错误,说 mongoTemplate 尚未生成,可能是循环引用。如果我将它添加到其他任何地方,行为不会改变
    • 能否请您也发布您的配置 xmls?我可能有一两个想法
    • 嗨 Bodgan - 我终于解决了这个问题,我同时使用了 ContextLoadListener 和 DispatcherServlet,这就是问题所在。现在我删除了上下文监听器,它工作正常。感谢所有帮助。
    • 你能不能也分享一下 ThreadLocal 逻辑,可能对我有帮助
    • 我也会用 ThreadLocal 部分更新与此相关的其他问题。如果问题已为您解决,请将答案标记为已接受,以便其他可能发现此问题的人知道如何解决。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-22
    • 2011-08-05
    • 1970-01-01
    相关资源
    最近更新 更多