简体   繁体   English

将MongoTemplate传递给Custom Repository实现

[英]Passing MongoTemplate to Custom Repository implementation

Project is configured to used multiple MongoTemplate s Project配置为使用多个MongoTemplate

Mongo Ref is passed as Mongo Ref被传递为

@EnableMongoRepositories(basePackages={"com.mypackage.one"}, mongoTemplateRef="mongoTemplateOne")

for repositories in the package com.mypackage.one 对于com.mypackage.one包中的存储库

and

@EnableMongoRepositories(basePackages={"com.mypackage.two"}, mongoTemplateRef="mongoTemplateTwo")

for repositories in the package com.mypackage.two 对于com.mypackage.two包中的存储库

For standard repositories it works fine. 对于标准存储库,它工作正常。 But for the scenarios, where I need custom behavior, I define say myRepoCustomImpl with my custom behavior needs. 但对于我需要自定义行为的场景,我定义了myRepoCustomImpl以及我的自定义行为需求。

Problem : I need to have access to the MongoTemplate which the the analogous standard Repository. 问题 :我需要访问类似标准存储库的MongoTemplate

eg If MyRepo is extending MyRepoCustom interface as 例如,如果MyRepoMyRepoCustom接口扩展为

@Repository
interface MyRepo extends MongoRepository<MyEntity, String>, MyRepoCustom{}

MyRepoCustomImpl MyRepoCustomImpl

@Service
    public class MyRepoCustomImpl implements MyRepoCustom{
        @Autowired
        @Qualifier("mongoTemplateOne")
        MongoTemplate mongoTmpl;

        @Override
        MyEntity myCustomNeedFunc(String arg){
            // MyImplemenation goes here
        }

}

If MyRepo is in package com.mypackage.one , the mongoTemplateOne will be used by myRepo, so there should be a some way to MyRepoCustomImpl will know that it should also use mongoTemplateOne , whenever I will make change in the mongoTemplateRef for MyRepo , say as 如果MyRepocom.mypackage.one包中, mongoTemplateOne将被myRepo使用,所以应该有一些方法让MyRepoCustomImpl知道它也应该使用mongoTemplateOne ,每当我在mongoTemplateRefMyRepo进行更改时,就像

@EnableMongoRepositories(basePackages={"com.mypackage.one"}, mongoTemplateRef="mongoTemplateThree")

now I need to make changes to @Qualifier in the MyRepoCustomImpl ! 现在我需要在MyRepoCustomImpl对@Qualifier进行更改! There are lots of repos with custom behaviour, so its becoming tedious task. 自定义行为有很多回购,因此它变得繁琐乏味。

Question: Instead isn't there any way that the MongoTemplate to be used should get automatically injected or resolved according to the Repo it is extending to? 问题:相反,没有任何方法可以根据它扩展到的回购自动注入或解决使用的MongoTemplate?

MongoTemplate isn't exposed by the MongoRepository interface. MongoTemplate不被暴露MongoRepository接口。 They could potentially expose the name of the MongoTemplate @Bean and that could provide a solution to your question. 他们可能会暴露MongoTemplate @Bean的名称,这可以为您的问题提供解决方案。 However, given the fact that they don't, I will provide an example below that may suit your needs. 但是,鉴于他们没有,我将在下面提供一个可能适合您需求的示例。

First off mongoTemplateRef refers to the name of the @Bean to use, it doesn't specify the name of the MongoTemplate . 首先, mongoTemplateRef指的是要使用的@Bean名称 ,它不指定MongoTemplate的名称。

You will need to provide each MongoTemplate @Bean and then refer to it within your @EnableMongoRepositories annotation. 您需要提供每个MongoTemplate @Bean ,然后在@EnableMongoRepositories注释中引用它。

Since you are using spring-boot you can take advantage of the MongoDataAutoConfiguration class. 由于您使用的是spring-boot,因此您可以利用MongoDataAutoConfiguration类。 Please take a look at what it does here https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java . 请看看它在这里做了什么https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data /mongo/MongoDataAutoConfiguration.java

The simplest example is this. 最简单的例子就是这样。

package: com.xyz.repo (this implementation relies on the configuration provided by MongoDataAutoConfiguration ) 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
    }
}

package: com.abc.repo 包: 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 will rely on spring.data.mongodb properties within application.properties com.abc.repo will rely on spring.data.mongodb2 properties within application.properties com.xyz.repo将依托spring.data.mongodb属性中application.properties com.abc.repo将依托spring.data.mongodb2内性能application.properties

I haven't used the AbcRepoConfiguration.TEMPLATE_NAME approach before, but it was compiling within my IDE. 我以前没有使用过AbcRepoConfiguration.TEMPLATE_NAME方法,但它是在我的IDE中编译的。

Please let me know if you need any clarification. 如果您需要任何澄清,请告诉我。

MongoTemplate is not injected on your repository class but deeper in spring-data-mongodb so you cannot get it from your repository. MongoTemplate不会在您的存储库类中注入,而是在spring-data-mongodb更深入,因此您无法从存储库中获取它。 Look at the code you will learn a lot of stuff. 看看你会学到很多东西的代码。

So no you can't inject a bean according to the repo extend except if you disable spring-boot auto-configuration and component discovery and configure it by your self but it will be much longer than just changing @Qualifier name. 因此,除非您禁用spring-boot自动配置和组件发现并自行配置它,否则不能根据repo扩展注入bean,但这比仅更改@Qualifier名称要长得多。 Your IDE call help you easily and you might regret disable auto-configuration. 您的IDE调用可以轻松地帮助您,您可能会后悔禁用自动配置。

Sorry for the disappointment. 抱歉让人失望。

You can use following example. 您可以使用以下示例。

1) 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) 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) 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) 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 https://github.com/JohnathanMarkSmith/spring-fongo-demo

You can directly inject MongoTemplate and MongoOperations in your service classes. 您可以直接在服务类中注入MongoTemplate和MongoOperations。

Try to auto-wire them and then you should be good. 尝试自动连接它们然后你应该很好。

Update: 更新:

Without autowiring with proper qualifier(since you have two repositories) this is not possible. 没有使用适当的限定符自动装配(因为你有两个存储库),这是不可能的。 As Custom class all together different from repository. 作为Custom类,所有这些都与存储库不同。 If you had only one repository then autowire of mongotemplate would have been sufficient otherwise you have to provide the qualifier in impl as two beans of MongoTempalte are created. 如果你只有一个存储库,那么mongotemplate的autowire就足够了,否则你必须在impl中提供限定符,因为创建了两个MongoTempalte bean。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM