将 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

例如 如果MyRepoMyRepoCustom 接口扩展为

@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 传递给自定义存储库实现的主要内容,如果未能解决你的问题,请参考以下文章

将 HTML 传递给自定义组件

从 UIViewController 将变量传递给自定义 UITableViewCell

Spring Batch:如何将 jobParameters 传递给自定义 bean?

如何将 googleMapController 传递给自定义小部件? (扑)

如何将 UIViewController 实例传递给自定义 UITableCell

如何将 crud 表中的行值传递给自定义提交按钮