我有一个项目利用Spring Data(本例中为MongoDB)与具有相同模式的多个数据库进行交互。这意味着每个数据库使用相同的实体和存储库类。所以,例如:
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
}
如果我连接到单个数据库,这可以正常工作,但是当我想同时连接到多个数据库时,事情会变得更复杂:
@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
实例创建同一存储库的多个实例,但我不知道引用和注入它们的正确方法。我希望能够将各个存储库实例注入到不同的控制器中,如下所示:
@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
引用它们吗?
奖金问题:这可以通过自定义存储库工厂完成吗?
答案 0 :(得分:11)
使用@NoRepositoryBean
创建您的存储库界面,我们将自己连接起来:
@NoRepositoryBean
public interface ModelMongoRepository extends MongoRepository<Model, String> {
}
然后,在@Configuration
类中,使用MongoRepositoryFactoryBean
实例化2个存储库bean。两个存储库都将返回相同的Spring Data Repository接口,但我们将为它们分配不同的MongoOperations
(即:数据库详细信息):
@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都针对不同的数据库进行了配置,并使用了相同的模型。
您可以使用@Qualifier
注入它们:
@Autowired
@Qualifier("one")
private ModelMongoRepository mongoRepositoryOne;
@Autowired
@Qualifier("two")
private ModelMongoRepository mongoRepositoryTwo;
为简单起见,我对配置类中的值进行了硬编码,但您可以从application.properties/yml中的属性中注入它们。
编辑回答评论:
如果要在不失去spring数据接口存储库优势的情况下创建自定义实现,可以使用以下修改。规范说:
通常有必要为少数人提供自定义实现 存储库方法。 Spring Data存储库可以轻松实现 提供自定义存储库代码并将其与通用CRUD集成 抽象和查询方法功能。丰富存储库 使用自定义功能,您首先定义一个接口和一个 自定义功能的实现。使用存储库 您提供的用于扩展自定义界面的界面。最多 要找到的类的重要位是Impl的后缀 与核心存储库接口相比较的名称(见下文)。
创建一个新的界面,它在技术上与spring数据无关,旧的界面很好:
public interface CustomMethodsRepository {
public void getById(Model model){
}
让您的存储库界面扩展这个新界面:
@NoRepositoryBean
public interface ModelMongoRepository extends MongoRepository<Model, String>, CustomMethodsRepository {
}
然后,创建您的实现类, only 实现非spring-data接口:
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());
:
@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配置手动连接存储库,则必须将此实现命名为ModelMongoRepositoryImpl
以匹配接口ModelMongoRepository +"Impl"
。它将由春天自动处理。
答案 1 :(得分:1)
对于一般@Repository
,您只需添加(value="someDao")
来命名已创建的Bean,如果MongoRepository
扩展Repository
这应该有效。