7

这与 @Document 注释中的 MongoDB 和 SpEL 表达式有关

这就是我创建我的 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' 的访问

我究竟做错了什么?

4

3 回答 3

11

终于弄清楚为什么我会遇到这个问题。

使用 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);

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

于 2014-01-10T13:19:57.407 回答
3

以上答案在我的情况下只是部分起作用。

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

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

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

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

private <T> String determineEntityCollectionName(T obj)

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

于 2014-09-02T07:31:32.460 回答
2

如果您在相关问题中配置了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
}
于 2013-11-13T08:56:35.017 回答