使用@Document进行mongodb多租户拼写

时间:2013-11-06 09:02:08

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

这与此有关 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'的访问

我做错了什么?

3 个答案:

答案 0 :(得分:7)

最后想出了为什么我会遇到这个问题。

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

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

答案 1 :(得分: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
}

答案 2 :(得分:2)

以上答案在我的案例中只是部分起作用。

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

因为MongoQueryMethod对象包含对此状态的引用&#39; bean似乎被基础设施代码@Document注释汇集/缓存,Spel并不总是有效。

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

我尝试使用AOP来修改此行为,方法是在MongoEntityMetadata中设置一个空集合名称,但这没有帮助,因为实现执行接口的AbstractMongoQuery内部类的更改也需要完成为了检查MongoEntityMetadata集合名称是否为null,因此使用不同的MongoTemplate方法签名。 MongoTemplate非常聪明,可以通过使用私有方法

猜出正确的集合名称
private <T> String determineEntityCollectionName(T obj)

我在春天创造了一张票jira https://jira.spring.io/browse/DATAMONGO-1043