Spring + Mongo +泛型+灵活性 [英] Spring + Mongo + Generics + Flexibility

查看:328
本文介绍了Spring + Mongo +泛型+灵活性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的代码不起作用(当然),因为标记的行不能编译:

  MyClass {
//单例东西
私有静态MyClass实例;
private MyClass(){}
public static MyClass getInstance(){
if(instance == null){
instance = new MyClass();
}
返回实例;
}

//方法创建问题
public NonGenericSuperClassOfGenericClass create(Class<?> ... classes){
if(someCondition)
return新的GenericClass< classes [0],classes [1]>; // DOES NOT COMPILE
else
return new OtherGenericClass< classes [0]> ;;






$ b因此,我实际上不知道创建将返回

  GenericClass< classes [0],classes [1]> 

  OtherGenericClass<类[0]> 

有不同数量的参数。



发生这种情况是因为我正在使用 Spring ,并计划使用 MongoDB ,但将来可能需要切换到不同的方式(例如Hibernate)。



类GenericClass类似于:

  GenericClass< PersistetType1,龙> 

  GenericClass< PersistentType2,Long> 

其中PersistentType1 / 2是我需要最终存储在数据库中的类,而GenericClass是类型的代理来访问Mongo API。实际上,它看起来像:

  public MongoTemplate getTemplate(); 
public void save(T toInsert);
public List< T>选择(Query selectionQuery);
public T selectById(ID id);
public WriteResult更新(Query selectionQuery,Update updatedAttributes);
public void delete(T toRemove);
public void delete(Query selectionQuery);

现在,什么?
从控制器(或实体,如果你挑剔)我需要实例化存储库并调用任何方法。这导致控制器与MongoDB耦合,即他们明确地必须实例化这样的GenericClass,它实际上被称为MongoRepository并且严格依赖于Mongo(实际上它是具有两个自由度的泛型)。



所以,我决定创建MyClass,这是一个隔离控制器的进一步代理。通过这种方式,Controller可以获取MyClass的单​​个实例,并让它创建相应存储库的新实例。特别是,当somecondition成立时,这意味着我们想要使用MongoRepository(当它是假的,也许需要实例化一个Hibernate代理,即HibernateRepository)。然而,MongoRepository是通用的,因此它需要某种形式的实例化,我希望作为参数传递。



不幸的是,泛型在编译时被解析,因此它们不适用于我,我猜。

如何解决这个问题?

解决方案

为了从应用程序逻辑中解耦基础持久性存储,我将使用DAO方法。

使用所需的方法定义DAO的接口,例如保存,更新等。然后为您可能需要的每个持久性提供者提供一个实现,例如UserAccess可能是您可以实现为HibernateUserAccess和MongoUserAccess的接口。在每个实施中,您都会注入适当的模板。 Mongo或Hibernate,并使用它来完成持久化操作。



您可能遇到的问题是您的加载操作将返回User的实例,这需要跨持久性提供者(即JPA注释)将与MongoDB(泄漏抽象)所需的Spring Data注释不同。

我可能会通过创建一个用户界面来表示持久性操作的结果并为每个持久性提供者实现一个实现来解决这个问题。或者返回您从JPA或Mongo加载结果生成的通用模型。


The following code doesn't work (of course), because the marked line does not compile:

MyClass {
    //singleton stuff
    private static MyClass instance;
    private MyClass () {}
    public static MyClass getInstance() {
        if(instance==null) {
            instance = new MyClass ();
        }
        return instance;
    }

    // method creating problems
    public NonGenericSuperClassOfGenericClass create(Class<?>... classes) {
        if(someCondition)
             return new GenericClass<classes[0],classes[1]>; // DOES NOT COMPILE
        else
             return new OtherGenericClass<classes[0]>;
    }
}

Therefore, I actually don't know whether "create" will return

GenericClass<classes[0],classes[1]>

or

OtherGenericClass<classes[0]>

which have different numbers of parameters.

This happens because I'm using Spring and I plan to use MongoDB, but in the future I may need to switch to something different (e.g. Hibernate).

The class GenericClass is something like:

 GenericClass<PersistetType1, Long> 

or

 GenericClass<PersistentType2, Long>

where PersistentType1/2 are classes that I need to finally store in the DB, while, GenericClass is a sort of Proxy to access Mongo APIs. In fact, it looks like:

  public MongoTemplate getTemplate();
  public void save(T toInsert);
  public List<T> select(Query selectionQuery);
  public T selectById(ID id);
  public WriteResult update(Query selectionQuery, Update updatedAttributes);
  public void delete(T toRemove);
  public void delete(Query selectionQuery);

Now, what? From Controllers (or Entity, if you are picky) I need to instantiate the repository and invoke any methods. This causes the Controllers to be coupled with MongoDB, i.e. they explicitly have to instantiate such GenericClass, which is actually called MongoRepository and is strictly dependent on Mongo (in fact it is a generic with exactly two "degrees of freedom").

So, I decided to create MyClass, that is a further proxy that isolates Controllers. In this way, Controller can get the single instance of MyClass and let it create a new instance of the appropriate repository. In particular, when "somecondition" is true, it means that we want to use MongoRepository (when it is false, maybe, a need to instantiate a Hibernate proxy, i.e. HibernateRepository). However, MongoRepository is generic, therefore it requires some form of instantiation, that I hoped to pass as a parameter.

Unfortunately, generics are resolved at compile time, thus they don't work for me, I guess.

How can I fix that?

解决方案

In order to decouple the underlying persistence store from your application logic I would use the DAO approach.

Define the interface of your DAO with the required methods e.g. save, update etc. And then provide an implementation for each persistence provider you might need e.g.UserAccess might be the interface which you could implement as HibernateUserAccess and MongoUserAccess. In each implementation you inject the appropriate Template e.g. Mongo or Hibernate and use that to complete the persistence operation.

The issue you might have is that your load operation would return an instance of User, this would need to vary across persistence providers i.e. JPA annotations would be different to the Spring Data annotations needed for MongoDB (leaky abstraction).

I would probably solve that by creating a User interface to represent the result of the persistence operation and having an implementation for each persistence provider. Either that or return a common model which you build from the results of a JPA or Mongo load.

这篇关于Spring + Mongo +泛型+灵活性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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