定制Spring Data Repository bean名称以用于多个数据源 [英] Customizing Spring Data repository bean names for use with multiple data sources

查看:97
本文介绍了定制Spring Data Repository bean名称以用于多个数据源的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个项目,该项目利用Spring Data(在这种情况下为MongoDB)与具有相同架构的多个数据库进行交互.这意味着每个数据库都使用相同的实体和存储库类.因此,例如:

I have a project that utilizes Spring Data (MongoDB in this instance) to interact with multiple databases with the same schema. What this means is that each database utilizes the same entity and repository classes. So, for example:

public class Thing {
    private String id;
    private String name;
    private String type;
    // etc...  
}

public interface ThingRepository extends PagingAndSortingRepository<Thing, String> {
    List<Thing> findByName(String name);
}

@Configuration
@EnableMongoRepositories(basePackageClasses = { ThingRepository.class })
public MongoConfig extends AbstractMongoConfiguration {
    // Standard mongo config
}

如果我要连接到一个数据库,这很好用,但是当我想同时连接到多个数据库时,事情变得更加复杂:

This works fine if I am connecting to a single database, but things get more complicated when I want to connect to more than one database at the same time:

@Configuration
@EnableMongoRepositories(basePackageClasses = { ThingRepository.class },
    mongoTemplateRef = "mongoTemplateOne")
public MongoConfigOne extends AbstractMongoConfiguration {

    @Override
    @Bean(name = "mongoTemplateOne")
    public MongoTemplate mongoTemplate() throws Exception {
        return new MongoTemplate(this.mongo(), "db_one");
    }

    // Remaining standard mongo config

}

@Configuration
@EnableMongoRepositories(basePackageClasses = { ThingRepository.class },
    mongoTemplateRef = "mongoTemplateTwo")
public MongoConfigTwo extends AbstractMongoConfiguration {

    @Override
    @Bean(name = "mongoTemplateTwo")
    public MongoTemplate mongoTemplate() throws Exception {
        return new MongoTemplate(this.mongo(), "db_two");
    }

    // Remaining standard mongo config

}

我可以使用不同的MongoTemplate实例创建同一存储库的多个实例,但是我不知道引用和注入它们的正确方法.我希望能够将各个存储库实例注入到不同的控制器中,例如:

I can create multiple instances of the same repository, using different MongoTemplate instances, but I don't know the correct way to reference and inject them. I would like to be able to inject the individual repository instances into different controllers, like so:

@Controller
@RequestMapping("/things/one/")
public class ThingOneController {
    @Resource private ThingRepository thingRepositoryOne;
    ...
}

@Controller
@RequestMapping("/things/two/")
public class ThingTwoController {
    @Resource private ThingRepository thingRepositoryTwo;
    ...
}

这样的配置可行吗?我可以以某种方式控制实例化接口的bean名称,以便可以用@Resource@Autowired引用它们吗?

Is a configuration like this possible? Can I somehow control the bean names of the instantiated interfaces so that I can reference them with @Resource or @Autowired?

奖金问题:这也可以通过自定义存储库工厂来完成吗?

Bonus question: can this be accomplished with a custom repository factory as well?

推荐答案

使用@NoRepositoryBean创建存储库接口,我们将自己连接起来:

Create your repository interface with @NoRepositoryBean, we'll wire it up ourself:

@NoRepositoryBean
public interface ModelMongoRepository extends MongoRepository<Model, String> {
}      

然后,在@Configuration类中,使用MongoRepositoryFactoryBean实例化2个存储库bean.这两个存储库都将返回相同的Spring Data Repository接口,但是我们将为它们分配不同的MongoOperations(即:数据库详细信息):

Then, in a @Configuration class, instantiate the 2 repository beans using MongoRepositoryFactoryBean. Both repositories will return the same Spring Data Repository interface, but we'll assign them different MongoOperations (ie: database details):

@Configuration
@EnableMongoRepositories
public class MongoConfiguration {

    @Bean
    @Qualifier("one")
    public ModelMongoRepository modelMongoRepositoryOne() throws DataAccessException, Exception {
        MongoRepositoryFactoryBean<ModelMongoRepository, Model, String> myFactory = new MongoRepositoryFactoryBean<ModelMongoRepository, Model, String>();
        myFactory.setRepositoryInterface(ModelMongoRepository.class);
        myFactory.setMongoOperations(createMongoOperations("hostname1", 21979, "dbName1", "username1", "password1"));
        myFactory.afterPropertiesSet();
        return myFactory.getObject();
    }

    @Bean
    @Qualifier("two")
    public ModelMongoRepository modelMongoRepositoryTwo() throws DataAccessException, Exception {
        MongoRepositoryFactoryBean<ModelMongoRepository, Model, String> myFactory = new MongoRepositoryFactoryBean<ModelMongoRepository, Model, String>();
        myFactory.setRepositoryInterface(ModelMongoRepository.class);
        myFactory.setMongoOperations(createMongoOperations("hostname2", 21990, "dbName2", "username2", "password2"));
        myFactory.afterPropertiesSet();
        return myFactory.getObject();
    }

    private MongoOperations createMongoOperations(String hostname, int port, String dbName, String user, String pwd) throws DataAccessException, Exception {
        MongoCredential mongoCredentials = MongoCredential.createScramSha1Credential(user, dbName, pwd.toCharArray());
        MongoClient mongoClient = new MongoClient(new ServerAddress(hostname, port), Arrays.asList(mongoCredentials));
        Mongo mongo = new SimpleMongoDbFactory(mongoClient, dbName).getDb().getMongo();
        return new MongoTemplate(mongo, dbName);
    }
    //or this one if you have a connection string
    private MongoOperations createMongoOperations(String dbConnection) throws DataAccessException, Exception {
        MongoClientURI mongoClientURI = new MongoClientURI(dbConnection);
        MongoClient mongoClient = new MongoClient(mongoClientURI);
        Mongo mongo = new SimpleMongoDbFactory(mongoClient, mongoClientURI.getDatabase()).getDb().getMongo();
        return new MongoTemplate(mongo, mongoClientURI.getDatabase());
    }
}

您现在拥有2个具有不同@Qualifier名称的bean,每个bean为不同的数据库配置并且使用相同的模型.

You now have 2 beans with distinct @Qualifier names, each configured for different databases, and using the same model.

您可以使用@Qualifier注入它们:

@Autowired
@Qualifier("one")
private ModelMongoRepository mongoRepositoryOne;

@Autowired
@Qualifier("two")
private ModelMongoRepository mongoRepositoryTwo;

为简单起见,我已经在配置类中对值进行了硬编码,但是您可以从application.properties/yml中的属性中注入它们.

For simplicity, I've hard coded the values in the configuration class, but you can inject them from properties in application.properties/yml.

编辑以回答评论:

如果您要创建自定义实现而不失去spring数据接口存储库的优势,请进行以下修改.规格说明如下:

Here's the modification if you want to create a custom implementation without loosing the benefits of spring data interface repositories. the specs says this:

通常有必要为少数几个提供自定义实现 存储库方法. Spring Data存储库可轻松让您 提供自定义存储库代码并将其与通用CRUD集成 抽象和查询方法功能.丰富存储库 使用自定义功能,您首先需要定义一个界面和一个 自定义功能的实现.使用资料库 您提供的用于扩展自定义界面的界面.最多 对于该类而言,重要的一点是Impl的后缀 与核心存储库界面相比,它的名称(请参见下文).

Often it is necessary to provide a custom implementation for a few repository methods. Spring Data repositories easily allow you to provide custom repository code and integrate it with generic CRUD abstraction and query method functionality. To enrich a repository with custom functionality you first define an interface and an implementation for the custom functionality. Use the repository interface you provided to extend the custom interface. The most important bit for the class to be found is the Impl postfix of the name on it compared to the core repository interface (see below).

创建一个新接口,从技术上讲,该接口与spring数据无关,是一个很好的旧接口:

Create a new interface, which has technically nothing to do with spring data, good old interface:

public interface CustomMethodsRepository {
    public void getById(Model model){
}

让您的存储库界面扩展了这个新界面:

Have your repository interface extends this new interface:

@NoRepositoryBean
public interface ModelMongoRepository extends MongoRepository<Model, String>, CustomMethodsRepository {
} 

然后,创建您的实现类,该实现类实现您的非spring-data接口:

Then, create your implementation class, which only implements your non-spring-data interface:

public class ModelMongoRepositoryImpl  implements CustomModelMongoRepository {
    private MongoOperations mongoOperations;

    public ModelMongoRepositoryImpl(MongoOperations mongoOperations) {
        this.mongoOperations = mongoOperations;
    }
    public void getById(Model model){
        System.out.println("test");
    }
}

更改Java配置以添加myFactory.setCustomImplementation(new ModelMongoRepositoryImpl());:

Change the Java configuration to add myFactory.setCustomImplementation(new ModelMongoRepositoryImpl()); :

@Bean
@Qualifier("one")
public ModelMongoRepository modelMongoRepositoryOne() throws DataAccessException, Exception {
    MongoRepositoryFactoryBean<ModelMongoRepository, Model, String> myFactory = new MongoRepositoryFactoryBean<ModelMongoRepository, Model, String>();
    MongoOperations mongoOperations = createMongoOperations("hostname1", 21979, "dbName1", "usdername1", "password1");
    myFactory.setCustomImplementation(new ModelMongoRepositoryImpl(mongoOperations));
    myFactory.setRepositoryInterface(ModelMongoRepository.class);
    myFactory.setMongoOperations(mongoOperations);

    myFactory.afterPropertiesSet();
    return myFactory.getObject();
}

如果您不是通过Java config手动连接存储库,则此实现必须命名为ModelMongoRepositoryImpl以匹配接口ModelMongoRepository +"Impl".它将在春季自动处理.

If you were not wiring the repository manually through Java config, this implementation would HAVE to be named ModelMongoRepositoryImpl to match the interface ModelMongoRepository +"Impl". And it would be handled automatically by spring.

这篇关于定制Spring Data Repository bean名称以用于多个数据源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆