编程语言
首页 > 编程语言> > java – 自定义Spring Data存储库bean名称以用于多个数据源

java – 自定义Spring Data存储库bean名称以用于多个数据源

作者:互联网

我有一个项目利用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引用它们吗?

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

解决方法:

使用@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中的属性中注入它们.

EDIT to answer comments:

如果您想在不失去spring数据接口存储库优势的情况下创建自定义实现,那么这是修改.规格说:

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数据无关,旧的界面很好:

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

让您的存储库接口扩展此新接口:

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

然后,创建实现类,它只实现非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”.它将由春天自动处理.

标签:java,spring,mongodb,spring-data,spring-data-mongodb
来源: https://codeday.me/bug/20191005/1857859.html