将 MongoTemplate 传递给自定义存储库实现
Posted
技术标签:
【中文标题】将 MongoTemplate 传递给自定义存储库实现【英文标题】:Passing MongoTemplate to Custom Repository implementation 【发布时间】:2017-12-27 12:41:44 【问题描述】:项目配置为使用多个 MongoTemplate
Mongo Ref 被传递为
@EnableMongoRepositories(basePackages="com.mypackage.one", mongoTemplateRef="mongoTemplateOne")
对于包中的仓库com.mypackage.one
和
@EnableMongoRepositories(basePackages="com.mypackage.two", mongoTemplateRef="mongoTemplateTwo")
对于包中的仓库com.mypackage.two
对于标准存储库,它可以正常工作。但是对于需要自定义行为的场景,我会根据自定义行为需求定义说 myRepoCustomImpl。
问题:我需要访问类似标准存储库的MongoTemplate。
例如
如果MyRepo
将MyRepoCustom
接口扩展为
@Repository
interface MyRepo extends MongoRepository<MyEntity, String>, MyRepoCustom
MyRepoCustomImpl
@Service
public class MyRepoCustomImpl implements MyRepoCustom
@Autowired
@Qualifier("mongoTemplateOne")
MongoTemplate mongoTmpl;
@Override
MyEntity myCustomNeedFunc(String arg)
// MyImplemenation goes here
如果 MyRepo 在包 com.mypackage.one
中,mongoTemplateOne
将被 myRepo 使用,因此应该有某种方法让 MyRepoCustomImpl 知道它也应该使用 mongoTemplateOne,每当我在mongoTemplateRef
中对MyRepo
进行更改时,请说为
@EnableMongoRepositories(basePackages="com.mypackage.one", mongoTemplateRef="mongoTemplateThree")
现在我需要对MyRepoCustomImpl
中的@Qualifier 进行更改!
有很多具有自定义行为的存储库,因此它变得乏味。
问题:相反,MongoTemplate 是否应该根据它扩展到的 Repo 自动注入或解析?
【问题讨论】:
您唯一能做的就是拥有一个基类并使用相应的限定符初始化 MongoTemplate 并使该变量受保护。 【参考方案1】:MongoTemplate
不会被MongoRepository
接口公开。他们可能会暴露MongoTemplate
@Bean
的名称,这可以为您的问题提供解决方案。但是,鉴于他们不这样做,我将在下面提供一个可能适合您需求的示例。
首先mongoTemplateRef
指的是要使用的@Bean
的名称,它没有指定MongoTemplate
的名称。
您需要提供每个MongoTemplate
@Bean
,然后在@EnableMongoRepositories
注释中引用它。
由于您使用的是 spring-boot,您可以利用 MongoDataAutoConfiguration
类。请看看它在这里做了什么https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java。
最简单的例子就是这个。
package: com.xyz.repo(此实现依赖MongoDataAutoConfiguration
提供的配置)
@Configuration
@EnableMongoRepositories(basePackages="com.xyz.repo") //mongoTemplateRef defaults to mongoTemplate
public class XyzRepoConfiguration
public abstract class BaseRepo
@Autowired
MongoTemplate mongoTemplate;
@Service
public class MyRepoCustomImpl extends BaseRepo implements MyRepoCustom
@Override
MyEntity myCustomNeedFunc(String arg)
// access to this.mongoTemplate is present
包: com.abc.repo
@Configuration
@EnableMongoRepositories(basePackages="com.abc.repo", mongoTemplateRef=AbcRepConfiguration.TEMPLATE_NAME)
public class AbcRepoConfiguration
public static final String TEMPLATE_NAME = "mongoTemplateTwo";
@Bean(name="mongoPropertiesTwo")
@ConfigurationProperties(prefix="spring.data.mongodb2")
public MongoProperties mongoProperties()
return new MongoProperties();
@Bean(name="mongoDbFactoryTwo")
public SimpleMongoDbFactory mongoDbFactory(MongoClient mongo, @Qualifier("mongoPropertiesTwo") MongoProperties mongoProperties) throws Exception
String database = this.mongoProperties.getMongoClientDatabase();
return new SimpleMongoDbFactory(mongo, database);
@Bean(name=AbcRepoConfiguration.TEMPLATE_NAME)
public MongoTemplate mongoTemplate(@Qualifier("mongoDbFactoryTwo") MongoDbFactory mongoDbFactory, MongoConverter converter) throws UnknownHostException
return new MongoTemplate(mongoDbFactory, converter);
public abstract class BaseRepo
@Autowired
@Qualifier(AbcRepoConfiguration.TEMPLATE_NAME)
MongoTemplate mongoTemplate;
@Service
public class MyRepoCustomImpl extends BaseRepo implements MyRepoCustom
@Override
MyEntity myCustomNeedFunc(String arg)
// access to this.mongoTemplate is present
com.xyz.repo 将依赖于application.properties
中的spring.data.mongodb
属性
com.abc.repo 将依赖 spring.data.mongodb2
内的 application.properties
属性
我之前没有使用 AbcRepoConfiguration.TEMPLATE_NAME 方法,但它是在我的 IDE 中编译的。
如果您需要任何说明,请告诉我。
【讨论】:
【参考方案2】:MongoTemplate
没有注入到您的存储库类中,而是注入到spring-data-mongodb
的更深处,因此您无法从存储库中获取它。看看代码你会学到很多东西。
因此,不,您不能根据 repo 扩展注入 bean,除非您禁用 spring-boot 自动配置和组件发现并自行配置它,但这比仅仅更改 @Qualifier
名称要长得多。您的 IDE 调用很容易为您提供帮助,您可能会后悔禁用自动配置。
很抱歉让您失望了。
【讨论】:
【参考方案3】:您可以使用以下示例。
1)
package com.johnathanmarksmith.mongodb.example;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* Date: 6/28/13 / 10:40 AM
* Author: Johnathan Mark Smith
* Email: john@johnathanmarksmith.com
* <p/>
* Comments:
* This main really does not have to be here but I just wanted to add something for the demo..
*
*/
public class MongoDBApp
static final Logger logger = LoggerFactory.getLogger(MongoDBApp.class);
public static void main(String[] args)
logger.info("Fongo Demo application");
ApplicationContext context = new AnnotationConfigApplicationContext(MongoConfiguration.class);
logger.info("Fongo Demo application");
2)
package com.johnathanmarksmith.mongodb.example;
import com.mongodb.Mongo;
import com.mongodb.ServerAddress;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import java.util.ArrayList;
/**
* Date: 5/24/13 / 8:05 AM
* Author: Johnathan Mark Smith
* Email: john@johnathanmarksmith.com
* <p/>
* Comments:
* <p/>
* This is a example on how to setup a database with Spring's Java Configuration (JavaConfig) style.
* <p/>
* As you can see from the code below this is easy and a lot better then using the old style of XML files.
* <p/>
* T
*/
@Configuration
@EnableMongoRepositories
@ComponentScan(basePackageClasses = MongoDBApp.class)
@PropertySource("classpath:application.properties")
public class MongoConfiguration extends AbstractMongoConfiguration
@Override
protected String getDatabaseName()
return "demo";
@Override
public Mongo mongo() throws Exception
/**
*
* this is for a single db
*/
// return new Mongo();
/**
*
* This is for a relset of db's
*/
return new Mongo(new ArrayList<ServerAddress>() add(new ServerAddress("127.0.0.1", 27017)); add(new ServerAddress("127.0.0.1", 27027)); add(new ServerAddress("127.0.0.1", 27037)); );
@Override
protected String getMappingBasePackage()
return "com.johnathanmarksmith.mongodb.example.domain";
3)
package com.johnathanmarksmith.mongodb.example.repository;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;
import com.johnathanmarksmith.mongodb.example.domain.Person;
/**
* Date: 6/26/13 / 1:22 PM
* Author: Johnathan Mark Smith
* Email: john@johnathanmarksmith.com
* <p/>
* Comments:
* <p/>
* This is my Person Repository
*/
@Repository
public class PersonRepository
static final Logger logger = LoggerFactory.getLogger(PersonRepository.class);
@Autowired
MongoTemplate mongoTemplate;
public long countUnderAge()
List<Person> results = null;
Query query = new Query();
Criteria criteria = new Criteria();
criteria = criteria.and("age").lte(21);
query.addCriteria(criteria);
//results = mongoTemplate.find(query, Person.class);
long count = this.mongoTemplate.count(query, Person.class);
logger.info("Total number of under age in database: ", count);
return count;
/**
* This will count how many Person Objects I have
*/
public long countAllPersons()
// findAll().size() approach is very inefficient, since it returns the whole documents
// List<Person> results = mongoTemplate.findAll(Person.class);
long total = this.mongoTemplate.count(null, Person.class);
logger.info("Total number in database: ", total);
return total;
/**
* This will install a new Person object with my
* name and random age
*/
public void insertPersonWithNameJohnathan(double age)
Person p = new Person("Johnathan", (int) age);
mongoTemplate.insert(p);
/**
* this will create a @link Person collection if the collection does not already exists
*/
public void createPersonCollection()
if (!mongoTemplate.collectionExists(Person.class))
mongoTemplate.createCollection(Person.class);
/**
* this will drop the @link Person collection if the collection does already exists
*/
public void dropPersonCollection()
if (mongoTemplate.collectionExists(Person.class))
mongoTemplate.dropCollection(Person.class);
4)
package com.johnathanmarksmith.mongodb.example.domain;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
/**
* Date: 6/26/13 / 1:21 PM
* Author: Johnathan Mark Smith
* Email: john@johnathanmarksmith.com
* <p/>
* Comments:
* <p/>
* This is a Person object that I am going to be using for my demo
*/
@Document
public class Person
@Id
private String personId;
private String name;
private int age;
public Person(String name, int age)
this.name = name;
this.age = age;
public String getPersonId()
return personId;
public void setPersonId(final String personId)
this.personId = personId;
public String getName()
return name;
public void setName(final String name)
this.name = name;
public int getAge()
return age;
public void setAge(final int age)
this.age = age;
@Override
public String toString()
return "Person [id=" + personId + ", name=" + name
+ ", age=" + age + "]";
https://github.com/JohnathanMarkSmith/spring-fongo-demo
【讨论】:
【参考方案4】:您可以直接在服务类中注入 MongoTemplate 和 MongoOperations。
尝试自动连接它们,然后你应该会很好。
更新:
如果不使用适当的限定符进行自动装配(因为您有两个存储库),这是不可能的。作为自定义类,所有这些都与存储库不同。如果您只有一个存储库,那么 mongotemplate 的自动装配就足够了,否则您必须在 impl 中提供限定符,因为创建了两个 MongoTempalte bean。
【讨论】:
我需要访问标准存储库的 MongoTemplate 吗?您在定制或标准方面有问题? 您能否提供更多信息,例如您尝试过什么。我从您的问题中了解到,您可以使用 repo 访问自定义方法,并且您想使用 mongoTemplate 访问它?或者您在自定义实施后无法访问 mongoTemplate?请清除我的疑虑,以便我们提供帮助。 @Mr.Arjun 你找到你要找的答案了吗? 还没有,这就是为什么要悬赏! 基本上,您是说 MyRepoCustomImpl 不使用您在 EnableMongoRepository 期间定义的 mongoTemplateOne?并且您必须使用 Qualifier 注入 mongoTemplateOne 才能使用该模板。对吗?以上是关于将 MongoTemplate 传递给自定义存储库实现的主要内容,如果未能解决你的问题,请参考以下文章
从 UIViewController 将变量传递给自定义 UITableViewCell
Spring Batch:如何将 jobParameters 传递给自定义 bean?
如何将 googleMapController 传递给自定义小部件? (扑)